floodlight-0.90/0000775000175000017500000000000012053411641014246 5ustar jamespagejamespagefloodlight-0.90/.gitignore0000664000175000017500000000013312041336206016233 0ustar jamespagejamespage*~ *.class .classpath .project .pydevproject .settings .DS_Store target thrift *.swp *.pyc floodlight-0.90/LICENSE.txt0000664000175000017500000002613612041336206016101 0ustar jamespagejamespage Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. floodlight-0.90/src/0000775000175000017500000000000012041336206015035 5ustar jamespagejamespagefloodlight-0.90/src/main/0000775000175000017500000000000012041336206015761 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/0000775000175000017500000000000012041336206017773 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/META-INF/0000775000175000017500000000000012041336206021133 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/META-INF/services/0000775000175000017500000000000012041336206022756 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootfloodlight-0.90/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModulefloodlight-0.90/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodligh0000664000175000017500000000251712041336206034164 0ustar jamespagejamespagenet.floodlightcontroller.core.FloodlightProvider net.floodlightcontroller.storage.memory.MemoryStorageSource net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager net.floodlightcontroller.topology.TopologyManager net.floodlightcontroller.forwarding.Forwarding net.floodlightcontroller.flowcache.FlowReconcileManager net.floodlightcontroller.core.OFMessageFilterManager net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher net.floodlightcontroller.perfmon.PktInProcessingTime net.floodlightcontroller.perfmon.NullPktInProcessingTime net.floodlightcontroller.restserver.RestApiServer net.floodlightcontroller.learningswitch.LearningSwitch net.floodlightcontroller.hub.Hub net.floodlightcontroller.jython.JythonDebugInterface net.floodlightcontroller.counter.CounterStore net.floodlightcontroller.counter.NullCounterStore net.floodlightcontroller.threadpool.ThreadPool net.floodlightcontroller.ui.web.StaticWebRoutable net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier net.floodlightcontroller.devicemanager.test.MockDeviceManager net.floodlightcontroller.core.test.MockFloodlightProvider net.floodlightcontroller.core.test.MockThreadPoolService net.floodlightcontroller.firewall.Firewallfloodlight-0.90/src/main/resources/floodlightdefault.properties0000664000175000017500000000165412041336206025617 0ustar jamespagejamespagefloodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\ net.floodlightcontroller.core.FloodlightProvider,\ net.floodlightcontroller.threadpool.ThreadPool,\ net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\ net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.firewall.Firewall,\ net.floodlightcontroller.forwarding.Forwarding,\ net.floodlightcontroller.jython.JythonDebugInterface,\ net.floodlightcontroller.counter.CounterStore,\ net.floodlightcontroller.perfmon.PktInProcessingTime,\ net.floodlightcontroller.ui.web.StaticWebRoutable net.floodlightcontroller.restserver.RestApiServer.port = 8080 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633 net.floodlightcontroller.jython.JythonDebugInterface.port = 6655 net.floodlightcontroller.forwarding.Forwarding.idletimeout = 5 net.floodlightcontroller.forwarding.Forwarding.hardtimeout = 0 floodlight-0.90/src/main/resources/web/0000775000175000017500000000000012041336206020550 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/img/0000775000175000017500000000000012041336206021324 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/img/switch.png0000664000175000017500000000401012041336206023326 0ustar jamespagejamespagePNG  IHDR@@iqIDATx?LYǿ7c-{/D_X!wMCJ)\D ("(5׮VY)c a.rUt*!B[<235661I>{~{313ZǏ3_ @#" `HX"7RWi>L2>jx|"B@ V^J)9DeF5{[1`]QNx=^x<.(B(˲`I ۥmY& [Umޢ2Z,MMM͈b1DUU!DCuK)Q(fNQ.̜4߰DDx|B h =:mrsSRH$ iȀn^Zw#1M{䍼RO[W + on7.({ަN\MrT"f^,+<66:2`vvv~냪T2@F[XܺuK ?]9߃P(Qdkל%{OAD7{`s"o2T +VXJI4HkPs|MWڶ  Wr1 ?*s=Wi d0??pi'!٩?ԀaCކ;^, 6TGhKDahtHQw4?j z[Qt@DvD~NG(t`C« B鰟Ytπx<>`vs__߱v@Dfö]2 =BCtv^] !~bouno3 ޾}ۖ Fo``$a<٭?; ;-&"i?«ֺi y~{&z.*x=8m@<0*t]?g뀭bEJgwAt)\hsw4`ZǏ;);::( q'05b䇑n"RJ,X`˲'@ޞ!@Wgm7xnBkPgшήNl7 2"=QgG+3_QQYiJg*** p]M=I;Q5@JKN׈vJ:KBephD5j!XV5G+3 X} G&iYUZ JZ K-;adsY,XhUZVQuI%7P4M;Aq>\|ģ)+KRs9$u wH&m붦}W)eYakHZk& *Yvlɲa =g;nrOFaXyw +<;;+u\'=. ,61o8‰D3?ަӸT xH$*5]놉[fnj(/z\5_ɽ|[g<}}OyӬIENDB`floodlight-0.90/src/main/resources/web/img/server.png0000664000175000017500000000067212041336206023345 0ustar jamespagejamespagePNG  IHDR@@iqIDATx훱n0Eo"Y?V/?(t C[A,CC­wyG2<9dj `l4[` l6-F8601#?cv^rZI)mhf9v{(EuR!"i!/aaѯoݏO `l4[` l6-Fh `Sm6 TGzPH7&0*"ޟEDVc?cZ{NN'F#f]^l4[` l6-Fh/Ѐ.0VIENDB`floodlight-0.90/src/main/resources/web/img/glyphicons-halflings-white.png0000664000175000017500000001040012041336206027267 0ustar jamespagejamespagePNG  IHDR:PLTEaY+tRNS/_?MOo ثKHuÓ'*zǽ̎sIDATx^흉r8h_fMp+̹J`pjt**qo }H)B~uY-o2Jl!aOpŷVcqJHR`f(WQY&)A^蜫/dկqX+bFcOS!paTUJwpIdt;fX^d|M/ LUZk!k [s#v[n'//j3Ǡw_ _/UOT=S^QooR;U|*Ugi[YsTfgXq}ہx?] R5j*IrH;z] Xȕ~(O+AEjSJۿ͈@DZT THUBGHl;??_v8 ށdg( _S@RXcx }Ș{vˎ+N5=ƥM^{sgcq#ϖsw*͖S}Tɒ+6L1ogl~ryenc e`5 u9!C0T 5j\]r.q_9p*߅hSm%a%T-JS>pʿO*)<$TerXK]ՕSgBv!miGzkdͫKJX|7ˑj:q36kqt8GՒ 2NSϹNeȽk[1_yT9NFKqpίňjQ`(TDʤ4D\-/- 6~T=Vy* AJFFҤq!/ b3C}@ط f-5jמ)$'@ހc|*䠯z@Z+ >#)[~OcDq_ux;E5{3)/Ry!"_T=MZ* FGfF8qo3a>8>NvʑF(4zQ}7T[~^i`>^CQF80KO\s%t5TUi:7Mq"@,\Gy幞jã<([omխsk>*"Tg'@q,ƙ#\g ْk̖:[uKWt l)%8UGW[߫JuV6TϻTUTӸuUG̾*귻 28^_uu1U1U.|'KH!ʋ,ozj^TS)I9gG=]k#|Du֩z5pru7(f?<-#e ՚zW߉EYE1m2oӳrgʸҚOv*VlS=YlP$!<.QM@OU>g6KPVlɬԷ>["vm0 ?>=Vhoٱnw!̰heK\@ҧKO<7z\Sgρ8mTR?7 mkޅ5mUۄPz?Sݩ|ϓCWY]]]]]]]]]]]]]]]]]]]m ]n_C{.[ THR#k0]bF>RˇZ~d @=xd~S0 @RvZA4-SO.a*U֠ $910v{Oȥo%9+f.@@AN3<0X~WT.o|p}0v}'~Tac1Zv^Lgu|K ?Gj1',UU_dTalL]~:C=CP4J`°Qݠ2 &nz&CDuJۻTa* ŧPe26T0}Q 'P D[Ne@:|*Ws|q]i rQZ#pcZ.俩H"?:xIpU[ 5ӈjLq SIPig*O{U׿W =[ `O7|Z|9% ):d+'Bl=EZnziՐlʺ^-0O+-\[|^Oi˷-oyoɾD%]dxg.z|f=>*8mq~_e2ɛ25]A5:"#Jyp>X=4+~"4VR?C0<.ޢj@tK/ٶM5zyDs7yKYFkݏAW%#Z$zjqkosEDB:HoiM39_,tt#Ύ޲6b=O;sG9Mu|qXO\ԍ|6yDG>G /"Pn?bO3v~1G{UT'W(|؃X+='Um*e`"N+U%JqDlߌ瓳T!>Syc%qoa/IB~ZxWJydFGj5fKlz+. bUoU͇ 9 Hqx˳Ϛ-}IW6H/J|ڜ ]^+kF]=}N 48E5r2ryVSe]oD/E8T3E &./g믿ַo|>ɭ?l2:cE0?EAkA쬣fsy??'u`D!h?*bƅQ,UmxO)zk{71LY&/7:rJt!PPC|39\YRea7r7ztyj}}sGy*{e]do}fX\3Uj{^`)z/7^V9.$`,LIu0SeM{xFydQ=JnߴJ&z Lot*&Yli%r*;ݢ)K5,U%{Lut)z|d?[QAF8g4vXQA5. {>LK9iDʥuG TngKȴg ") is յ[o&~ZS(DMʀ*i+ʔ`\; s敍eh+k!~ J.l01!i!FBa{w;ƒAߣ3}(mzFU;2j :X?38\ϜWFȲ6o%Ԋ9 /rfI <@ B]c[8y >%'lA+gbf \(y]\*@ Mt$UD6~T%~ڋ8v<OM+=ʏҰ`* 丷TUr&I~ [ʼ>dw?uYsBue)>?' pPUR,)Aeh)&6-K^Kˁ/mfIAkl{ߢ:7#cvuv@iCǪI><X8/Ozk -|!`iG3kUaFTtǏ 3Ih7Y uǙDQ蔇żjR$Ƃ^9fb,qJi4l̃BH>ʋC( {iG#BF3KPTX@ahA"AvV\|@7`^- 9-g02Yqbk ^ gpСI;]e[ Bt' y C؅իV RSQZ\7L]3#bbP ɔee8~6A|fVdGbǎO@| N>8Nz\ 4 ˆvOヽbߚ<K*+VDkh A"Fs.=.hz6ͫTVTa߾_o |fb|ee>@&y`~i6?h;>ܻwR?ط-] FYÍoA X4LRvo{{P;AU$R̲ąixg85*4./nfPq9yw7 Jَrp!' 3Yrˉm\i8ze9b:S i+ED4E8k?) `wаgF*Row(U]D ##LZ1J$5]~8Ê[-<'5Ga810XCqǒ%N;|P`/Pl2KH#!<߀;9€C#sOv0ao7DLQ6e`J%Ӎt+Ux[yt8n>}Y"g-G7` r){J1xC>D 2 ?c>Kdzak^w~T T*UΟZx' 9yuu錑Pk:@s'=( \ P^]NA^(wyt!E˵sO-N%K2Lz"W:,ZYFe8aZ4%A18\t%M)JBc Ne.dx4sf0p01FPro<;lFp!:ѫT0ɧ]9V؄4ْ|T4cX&|p~9vS1)|հT?%%ܬ8VMQf.}@Y~HB!`I)3 u72 gGkxT9%UPyƅ ci-7-bP)`DtشHgt SLWB$ZqӧNbݺuWyk/^NLVhxEJ$IߦF 󙾸 K nE@ w{Med/[s?[aŚ"̥vGg\%YցV~Ձz貰 ܁_z){W<6ė)agҲ2 E*bi*i-͟GQ2^|QDžY**Q'2Ïr/v:8|zldn2< Lwt;w:+-[:1]5|@ٴiztq BBݼ@b6LR4͍A%i=тSmmN޽Fʓ?N*ݸ'ae{vcѢPǙDӧOCmm#G`퓺] znW]h[uwu7:;;q+JD-BcELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC  !"$"$C<"> !1AQ"a2q#3BRbr$8CWsu-!1AQa"q#r ?*( hQEETP4QEG⊊(B("(+\s \v2%ؿ[rMVR!RH8=CHs]E| |kA']pcy*cb.ek yTUI'Ingq"sw~uFyz XIoŹc+Ii`|ن+ mp#+I$y) Ҡ{ |Vg5~/"zٴR?_'-3*sI\uIeH ekE _B;׶fOe\"sKZy hr**hB+ÎOt:ڽ;dfr\QrZaYm':BFI$ F5Yqމ?P[+&@S $pi Ege^RA$ʶO͞&{K\Z{#ET\zA\z?u!K# ֡s~2+20qBϯґ% 7}o,$$G|6M!HrdiORڶ;~ 4|G6<ޔk&2GPG1IIj f;v'&ۤ6eJKxyߌ1hJd6Οf Ruk^;uU-PPW㺲' 14l{n~#Ҷg']cTFO )ὸI+IHg@ZXmƏWeM PP qS*5gx956r_sZ: #(?uhVnG=7;VRZڿJqA;RN 2ҷ*S.͘eS?HVO⅝r}"mVOnUla5ƚs"eˑ 6TؑDu$@$ fF!]oOS1) ]ҐwvvDew {TV,zͦ!Ci$JII*$I&h^PE~( ~7)͌. z5$5U.wۃ_?~.eLamFh8 Z:)JRI@kEDҭ;i*z&ƻL=WHRVЗ|zO ޫ w,/~O[`@nBTRԓ讔(N) gA#@65~/-VZFq l~WvW6Ls-1},?&rXkCc:hwilKI'wQ!8 2<8I\8G3.e{6ӹ'fkm [E4IPRUR@;ȁ߿f)<+lvO|>R۩Oԕ#؃"?c寈|rC5ga%_/q~y E!zq'qWd'[ʬ\ɍg|u-r>*͵-3`JA5+q.ZqaSIeJDe71K_Q#/@v*n6̓!ˮRۊz# JA; HJT@?>q82`0E:JmIJSi0~Vɯ(l&EDE-D!HQJU{k=h92,gcvjekj[ ҝ_2?eq%uʿ+lǞs## _BI$o]]|I񅷇L:_8Zu)+JҭoD$$ؑWg/n7kUbPeIr3Yww}y͜Ys.*b"zR DeIZ~b_Ń2 LPm~hcV[n;abFAd2@ґ=e"w)Y͌=tK֨u]D2NwJI w|!f86ͺF=& r!z J:RR#T$ Ih\ilv[Cy8h8*I:޷y=YJ$j#]9)'޶3-3b;.c[nO mfS()^"#:rs xHS-Ja$ GS0um0_;6{UnPI c~{D)Acg]DtR){٬|b!6q":x1@,b&x1iA]>WV5j:N<z"`[mqX†'M2_ѯoף{+֑FzqF$"tn)tn)tn)tn)7FBHy"f\M6BKgJ iQPhwr5rF֢7!Nԃ OHyQQVF\WTlZB[m BR4ڽnd6Ie]QDx.u$k I WtDl$ Tc&2'4Q%G);JWvkMsltPM.6R"c?ڜ{䙒!#Z׷7c^ o7>>Sح5'7ncm;NWd1lw ܓ`Ojk;$^./.t mJP:M2F+!aVZIР\s߹vˎ+N5=ƥM^{sgcq#ϖsw*͖S}Tɒ+6L1ogl~ryenc e`5 u9!C0T 5j\]r.q_9p*߅hSm%a%T-JS>pʿO*)<$TerXK]ՕSgBv!miGzkdͫKJX|7ˑj:q36kqt8GՒ 2NSϹNeȽk[1_yT9NFKqpίňjQ`(TDʤ4D\-/- 6~T=Vy* AJFFҤq!/ b3C}@ط f-5jמ)$'@ހc|*䠯z@Z+ >#)[~OcDq_ux;E5{3)/Ry!"_T=MZ* FGfF8qo3a>8>NvʑF(4zQ}7T[~^i`>^CQF80KO\s%t5TUi:7Mq"@,\Gy幞jã<([omխsk>*"Tg'@q,ƙ#\g ْk̖:[uKWt l)%8UGW[߫JuV6TϻTUTӸuUG̾*귻 28^_uu1U1U.|'KH!ʋ,ozj^TS)I9gG=]k#|Du֩z5pru7(f?<-#e ՚zW߉EYE1m2oӳrgʸҚOv*VlS=YlP$!<.QM@OU>g6KPVlɬԷ>["vm0 ?>=Vhoٱnw!̰heK\@ҧKO<7z\Sgρ8mTR?7 mkޅ5mUۄPz?Sݩ|ϓCWY]]]]]]]]]]]]]]]]]]]m ]n_C{.[ THR#k0]bF>RˇZ~d @=xd~S0 @RvZA4-SO.a*U֠ $910v{Oȥo%9+f.@@AN3<0X~WT.o|p}0v}'~Tac1Zv^Lgu|K ?Gj1',UU_dTalL]~:C=CP4J`°Qݠ2 &nz&CDuJۻTa* ŧPe26T0}Q 'P D[Ne@:|*Ws|q]i rQZ#pcZ.俩H"?:xIpU[ 5ӈjLq SIPig*O{U׿W =[ `O7|Z|9% ):d+'Bl=EZnziՐlʺ^-0O+-\[|^Oi˷-oyoɾD%]dxg.z|f=>*8mq~_e2ɛ25]A5:"#Jyp>X=4+~"4VR?C0<.ޢj@tK/ٶM5zyDs7yKYFkݏAW%#Z$zjqkosEDB:HoiM39_,tt#Ύ޲6b=O;sG9Mu|qXO\ԍ|6yDG>G /"Pn?bO3v~1G{UT'W(|؃X+='Um*e`"N+U%JqDlߌ瓳T!>Syc%qoa/IB~ZxWJydFGj5fKlz+. bUoU͇ 9 Hqx˳Ϛ-}IW6H/J|ڜ ]^+kF]=}N 48E5r2ryVSe]oD/E8T3E &./g믿ַo|>ɭ?l2:cE0?EAkA쬣fsy??'u`D!h?*bƅQ,UmxO)zk{71LY&/7:rJt!PPC|39\YRea7r7ztyj}}sGy*{e]do}fX\3Uj{^`)z/7^V9.$`,LIu0SeM{xFydQ=JnߴJ&z Lot*&Yli%r*;ݢ)K5,U%{Lut)z|d?[QAF8g4vXQA5. {>LK9iDʥuG TngKȴg ") is յ[o&~ZS(DMʀ*i+ʔ`\; s敍eh+k!~ J.lĸ-\c@l߸m }P CP.TBgse: @ h ZVo$`E! BapBB") D qъD"!&5$@#ّHY$iEz 1Ƚd و||D.!7P }irFPѨ{37>}lF!/ȋ{ KAU!LFaLhxCqEIJT4LT6QNSnS"R\EZjO5uFuurQ +ŎGy0HӸ٬QKV+TAk~5;fg'u:>::T*i=a=?Z!?(|14cxidjcoL2v6.502 49oljjz mfivlԜϜf~|Bb]Ke崕U k1qQk+;qh{;2788z;68;8;9K8;w0xsjZ:&ǭם=ؽQ뱶x牝sY#w% MqiAVQ|}}ibڢqmBځt K?jZ A9%5}"z926 _%3t&$^IbNHKJN~br6JK-{={JNHg~? W/c&4|CVLAV>+/QBnQ5zz|ͳ磞Ͽ{ec9^MNT|46y{hoqzl68;c. M[o-,׭v٭Mke7oo'()/_ᛛQ] ;<wny`, BP4GsH2 %Ccp w]@h!v3b0+"YZXp\9χ"H*sx'E-! 2*jW55= v^s2h67FHYI))R.$Mp7'@e̬䃱"Cs"s;`'%'J(@9PU^Y3S9PxBť&%z;_o9zt oS:2ujq=|3yセǥ{h ~~zr8idvy /y^P}]4i990> fy+|B;w߷(q|Ϥϫkc_6X~qʦ&>pb\k~Dbiohiq~zB% cUk2eN ._*|Nɷ? ؊ՈJbVq;,QWFU!5Muk M#NֱUڍ:mz r˸iYyeG#6Svމ"*&A٩i[χBU Pfv] ȍJ6! VąS /w2.~aovZ> iY;T]s)VރÃG^|.ǘ P*/v, 8PYVT^{jEʑ3SU k6j$E7𮑩IRWHz^o뼾z|_{FGήOөU=R{ l#QȰ84Mdy#K[ǁן/ rė%Ji NfSk' wN)gīzKS)55wip,Ux#gM66pԲ6]v6ZN". nnR?vy ~sOwxl" ~2".&J}bhxe k6O+yVET鯅Tϕ5_ިdwr\+GV\[nn Rm۱Nmp7]{Ht>tW>mB$(O,$n023j362 10p4K$;@7lAlQk{98KĹsp_&`*F)$#|PDN)H #I^/RϥoʞkRRU8)pdSR߱C@PWBwIM?PK6ӽf.V:m[};3{{7G_H4cunG=V\pǡ+0@h¹}:gHsd9D)y1 &fcKs8\n/ߏNDwnފ~ 3D[bC=cS%sI̢rU͙m=Q)ƍc1;ޣ||oK#\!ka1Zx1cq.O$Hde)rV Fri{R4j4{>hsң  Í3M L+.?\&HrsqZtartqh۹_ ү,P&(57q9M`GlYhs]ґǩ{}-bQV!|vT\E'˂OT5XsB /]Qiqx͋::_w!SO!a:/ '&=fߐN,X4XqSZQ=?~n8 t4!qCpLɃB,B AnAFuQeJCDm)dmx[`a&2Tl\7I UM WX@f8˨̴ȜE"abz8t98Oqrc;}Ç{ȟ+`Ef%O1)_8RC\L["ATҐ֖ёՖ?D ,⤚vB2ųL;EUA?q)Ye5i;9NGSF8g;vbJ^F  S {5^&2=9'=i8PetBFn^J~~BcwOPN>*-߬T8^T6^܋e/%63_oQm٦sM[gڥ:z;ú6ݷ~0ߓo406?\??:x)YSo<ޥ.,z_!c'U5޵ǿX|Əou߭z=D0ˏ͟p1wb[^X=5/EYk pHYs   IDATx]Uo}e̼-NH "BEDuuUwW(DzOPCIBIHH2%?&! ktQw߽;=v~G}_=z)K^ 0*֨襀Pz8N) OiV腧^wp1b@"vTʙ|.tXpp!ߎG +u D1ϩ'Wq"isx$_]XK:_yeS@QP*I3=w4 N=_G(0JL-aj-?Mdiʀ,tMW蝛?@jc Þzᩧ)[ޱtOquLSdL&:i`0`Vfz 5 c]6 eOh) OGKwt:麑qX"SS]e]~`о奅zx |uNEYB[/R#<:tAz_)3Kw647oPnzI77u9)&s+??wHnвL {e^@7 }tJ/# i3Nss;,ڲbQ'73Q79f+ fCf?}aDr#nL={ }[q, OǂeZvmLZ@\v*en$QG!D腧$foQ=JMfOi~@ٵ?^xN5oQ2N."TxI={;e$na *GkJ _~EkK߸Έizmb75;`_SRn.4]?q .ML66jkt|ڄxQDxJYqJS@FK^e8gUַ~fjR$W'*S?gHT:~ߐ\ %/f`s/K:?sᩁ-C8ދ)uNhnnTz~ mλu3YZ0ri5US =Zvϖ[Z/zؑ,߻oق~bF)ǒ 7<[63|ͰnG(XLۮKēIR~_YX?eҀQ_F#-(EWE)ں:뿮ټ櫟2,bX_n,=]YM\ǫySNjM&hoq=EXg]遇/9sQ,uttKGtз @%,,NFn} `}2 Bbѝ8t;fǖT{{1gUĞj_O̽U5#-xu}_9Zxc2J=PZfkyZO5Bַг=&boizdߺioxqI-3H9.3v02ݮe%]&BU z;LwgW]^?mbzn{uS%HiO&7?q|oX*ϫC AjVpH} o \~ũP/<1N% ʖ5 _tӧ^#4|,B*6'0u,b, ׌ l Rts56?d:> <9  $v5K- ,Sσ:<-h <ӴKj~.-t:Z:)!z腧io=C9g-J/>+Fst AvroZQ] B("S%UF@fWd%X#3 $ 'X&䍦䏒^ WeWQWzY[)ȧ{v <6l)K4|2|т>}?p!r ^x:D-(+ o1> \(ٰ #h9kլ\݈hb'|)8r  4|3g󩛹a©pJ'ݼ3{]Qf8%AvM߱;HT\63Ef(T0c|N&-pvb<5uVLњђp(x{S6VwĮ(w$1KA\rQ]to\4#rqE+'_󼱓 5D3<& OHQ 夻R!?Z;,pA,8%ĢH{il6>¦ 'Z m!Eȡ"Z}bp%S/좦ƕ+Vwu5lOUѥ'///XocMT/\/I#/Or`J.&!P4]&n XڟIEB@Ů$gt:1&XG``5fǾܺ8$MYsuBbț"#@)!\-ON>/^@?ɬEա{PE<,,ezPS-).uyyoE9d0}KP`I@m8Ӿ`4` ?0BqQءYijww;@r;HzqFr|wvJFLD0%lEmСN:L$RJfnAbn3/CH8de׫wwmoJ|~hPHIu*PyFɻ w!%!zP?܀CU-[soa)nM}K;12 1眥9ċ : 0!.=SpCNr\6mmwB#؏$⩽v5T7ڻ{K{rҒ>% RQZZՙ-عs~YL-I%j_DrA=O bSr@xܚ zwrsΘ9;?l6+w 2Ep)XEH+Y #\`22\~qJ:'ރ8,aiݑ({!94f8e|; NUoGG(i|q_Lmkg=|pʔLI5&L$8q,@0,_'0-k)É~wzN q(64[7Wz}]*r05v\Q*,X,]{ϋϽ`=]|7|HW* U 4g5 -[s7驍ᜂ3i7=ȧҼE\A Q8#'ٟ Pk{!oB!+/%tQ2V*=@.Z uW,>+{d`. ivN1N- ;4-Ɨjd/g`$TT$R7 @,+}ak+˴PVP X.˾^>%$Czo_@d:WHM)U P DPOj-k9aGҒmջ,h1kp7AGhH*"DDT1-uR>Oڦw^'AtUw =CגXB+zEBmpU(02ŋ6|}tn.:]3Ҫ*rYKhQQbj89ej04 Yx"JcC)Ⓖ7~D -U~ݑ~`>$i 7ږGƓK,@srYxH݄B{/UF8 Q%chLPźZA;GQ v SPNYEdf pr>N'2g Ď7hf.3`D9!.$^3lg=I 'bwEy݁R\͍<aޔwWO3m_~E,M-_>Զ~ig;CYZt1da?:\c.|`U~|N"D916i"$ob mk׭s2YQO%>´,,, Cc7L5] [u)e*^V89X6:=U٧~3Ϙ8pP_*L/\rú-O;hP+$6$lm[,Zg^k!&ӯ̶}L0L]<&Bt~`ܳu֮ݐ_?}f,)&}QT^S}쵅oo\=SD2" n~y+|ꋴ\6.w;[p[n$LB;ch| QXÈ%voqmy_MI*m;y eɗ/5-T,Mf^fOu}&ݜpUOj[IĞHxqXc[K7^uLn6d d L &qBʻE6?qNa{pr`{^>0r`ۗnl:6:omݐBW+3sʍ@,5C]ۥU9z d j1B o{IxvuL\T@B 78H$Da_Y=,Ci?۲2  `G:'3lƽ-{&'͎d(bwtv yv ےiFi !I::Z ADbFKa-L`ēJ⯿S=#cҚM@ @ 1rYb8~EɳtJDZVlٚ8MjZfæJd#VDGn/ʻb_l2_Fs V IDATxϝ?)w7Y۪]֪֊  |'8g/kYLB3A7/-rpGA[s;VWԦi!_KrdvO6|} 4Wޠz2lɾeF;r#4ȷvcݯ.[VMcH7CEUuMGOm\u;C11룤n|l@R4&J$<:Jdv([u6sn)[MN*!?@`Ah0ZMGڿ{ m,q|%|/PKn9i| e5;OKc$#"@&e쉄źt ӓ,;FR=(Kwu{uPi\F.*^"Fn`Hlz08!_-+# Ϭܽ13*V+@RxF+zɉ4y7{Ͼ+m~ Mrvo&Xȡ%Hl2"^/ t! k2><&*$3-(E"(? }H֧oysNZ{Pq =A#cΦ~eܨYɠig$ 7\>{@neb"L"t(N}\snc!4R=?w<:照ޞ3Nhac3pi>H$%"I E 2(C&0`D^"n:TOdo&\t= j&ss})IJPovˮ<)(H+!'+AWmt0vgSzG(K0O" VUT`O!b³%^6)46`xu|tA}'^J Zgw-zusMvun( ~y:Q/`Gw(x:dy33}:-o|aCKY0m82'EUg=Bo_!v!1J뮰ܪG4%^sܬJ@,!E:`(gE6!]KY /+թQ4+JR/THpJ=XSQ(E;jJث۩97^EpH|%ҚxExw’3κDػ /$bw<E%@" B?2BGRD;E#(w9rf}l*G vFH'eS$?xJtF1 d:yמ\ů\aN5BѼଳ'O3䭷-|euuvc~8VV*B 2>q4'2ts/xiFgpĂSQo߾{wh ^>yMu tr@?Z/l\I8Q @BxH}A2OI$M7oqS#0 1DFfEM͵ <mPۅ$m Ju44!kc'Lo,2PT{Yj!#RJxJH곰Țʪ`ac:lx)Kѻ`POaEe7RdjbEtKqת1m$]H"MOl/[o,A1xx +cJTZƠ"IlTT6=v񤸢TYJ +N*>\2q:>_ =//.q58tH۲[i !^) *KAWQbM? ).c$H YId8l+99" KwHt*;-){Oo(z˟/= _67W`Z@ 94q;w6mTu͞Tٲ7ޙrBv0-1G?xh #Hb:`T%Ǒɭ(?^z%CZ!aj7HS-~e?=!"QJVz%3M7EDjsvfT4;v$<(sP;0 WirFJ̸~8G?cjz+Vo_p"٣n>pDxmCfP~g~%|'.+`mҏ'SxxyD8'󂡐aYnwTIE8Ix"Rn*l#r"@0HPQ%p5gߡJ] TɄcbɦ׼ :TTG * %PEb*/[AU#}tq^Qa)FRh|XW~^ #E ("R슥]ɮή%愂v~4777hdC:w bfLHQeE:Sw7tw54༗]<4R\ U(m{Z~]tҏuyw߁ 7rhPziaaYAԉ+mF F0Z+EaVTJ$LX  &ˮ:H6%cR N "ef;M$S|*\}]L5rO|6OTq¶wgƧ >>&aFS3Y0&[m>JPN9*ʏjdL9ȞPCR|gsfMAq]}A9/G'D(qEgwAwH 0,`z:C09,]FG[b[w,]!WPPзoYye S=%a ߐN(Jy!ҽ& 貤{vm\_m@܌Cӿt܄acbVO7mTNfsjz{GuVn_l;+ֵ$ -syy Uqaвܒ" aA.9GZTKc˦]?׭M&U¹\z| Zh u 3woƍ[Wyguc-1h,7yĘу"(C_,@c Y]+Wlnnn[A76#G0uȌSӿ$*I۪9^/ |_q`I ƣhȨԸN%8ld` Ҳ]+2Z&I&P SmBa9F+d߿߼']?}%W^TX[UG5OQE\J0/z3{3\Z|Aq؛™nڽ3>oFRdʤKǰZG^S :|(<ȈK}-ցx kEMkv #'~tӑ`8$eV1™CSݳƀA Ylde+{]->~"k{v^rO> f0mdIIo3DDɄukK/{t' AL+Arf̜0GY)Rp71`G^_ۺO>;LPľq-vx 6`kB$2?D-3}j,xڹ7i䑣 -6uKm+S[9r0P ^㊶˝_]sYs.6hP\`.6"fM3R;;?lB—GONAT,rņooxa|%3. P a=.'%A-w' U}W"_ y\g*Z(GsaJJ80i[ `͖e;<ͨ[~~=s/?4x`DL% NIbUbv@ AFYy*hYh72clR[Ԋٿ=@ϼ ۭ-WA%7QzVheG YChlyΚߧʩkLJ ALFXX)=h/X} ݛRvggjͿ_yŀ?= &U/U< .K.9|d;*wQZAokI,[_>5=!{6a,Ѝhl=Ǘ^[믚3grJtmEv_>/%Y;b܋r`&##Ltl.38%\n)BVW}?WҜXb{fc쉀K@{e$n_ͅ70Y5G4[F5 ^+ĺZ WN?uDaa Lj*ˌMā'0+XA>XM̹21nYby.D_5xg?7/(E%a)nM]m]CJ55> /d8oAa8 $A6=Ñ( "NHv(zY#e(*4> ~F|)<5 %LbXx-GorD93DFJZu+O8C0e] bwFMY:(a2~wŃKN X'p  $;̖-;kO,oBB^ёz{k!)F,,p&jVf2 +Hl~Bz]k>wuCT)i2]-??>C9@^KByʈ6Ld:qqÐKp <͗͐L9!@(͛zk ̞j,m`9$ G V,԰O}vW[PtI^!,hdVKL([R"`@14r2aI|pqΓa#+((i-}b– KMM`C!|EUv z_S Q$Q1fST3؉}~_>d2w wU3 KD. qۓ;֬ھmkn5TnjhVW<pBₒ>?a11瑝$Uܦ5i\V=cf:ȴ4uS_״55[4A 7k*Bb9a먥D>Lꝝ}gl+ K@`hp'k`@H'/#cD x挓O:bu [>=iCoj/RCwuOUuU}w_\Rk~qz/haa"޵u7^_+qo?DyVTl ~YhjvunVK[|"4iij?6'Yc v#}-kP:DrgumCSwoٸg˦jS߿1%pXD8`0PUdlH쐔b Q -TJMrO.V4?dʋ()+SkƗtE$8"ˇm+\XUf%XFFݱ c]VVS0:[RssCH7HҼ;hжdo~h[rw2!wFSq+ ow0ycD%3;=C /䠉وE'~3O^zH@! Tbw K۸!YeFؓi_z"9`3hY!@x.D>׵Ooò%L_gDZEyH+'nLf4;>X`,~?rİq!J' .,#É`(#h8bMX<@ 21LA'W. SM?_ 7G~$I^FrOn"L>e5GiJwTAV.F L[=:mL-^Z۾b3λJ / i'AGhQi8cWuö۷սx%ڧOysN;~} n_]YNv,B= SDP'8%D0AF [j*Jb'EU `0cO3&3 UJefA9vRʁ%|dxa$mw?{!oP0|bys' sD _ UR*F_-à 42_7:v肢XnsGMscw7vv泞H0IӇ\z\Boinw5֤Y  FGZXT\Vuw^e]cW<@寈 v~}cSN= -~o~ ZJlBteNu晧E򂮮d+ko|guMr/!̌Wdh=օ 2`K{ṥ<.l+p~ECW0ț[wܼfֺDL;Xm[gwǝ?{Snq`rq]gu؀2Æ2uԔ*+i^\H IDATֆonidWȶoĩg8д?>s҉#XSQ/IVeG_eGV*Eo{p·6,o Љ9W^?]V"Ƅ'H ݆.4>IqBb3/{/f85 v&>8m&5]K\Sh5j6x萾p*\heA 9qAVGXI1'V_YP2xJH̹ʲBk4<;r,LH(V2 E@D%^+8Ff8a#Mj;w"F)"HHꅈ&#}ʯzwko 2X %1,_[6{ 9x=x^7s.yisH."8QW/>b{Fra`ܝ=zJgxm]Htl# 3?6fpĜQN2/~,xt qC,BONp( wlkI֫P`wç/=g #*hY˜uILcBS 7zBv`@:?gA[&bIO)G䣔Ǖrԉ'%ET͊F_5j~v"c!,0t=;;X겫NooK?7T;5#3ϝ߾IB5!дF0w!;8O$Zd%]v֭{-\ [iRdai _fR aas'O'`,Idl (|hWC,]v:@AS#0xXɗiƨ cRbn'[Κ,<30z Ý1)8p,W k?z dnW;Eb$7mx32?՗ATB3N\+I ty_~@SWFڽiV" Ke}9}F2o͢El{Æf*^1sR N̈,$e|rTuɶ#s  7 )> %qpt*h A}r8p~O2GףӎF(cA(`mcDF*9B) &dhAA4@7*U60C <^iqvG>iY)1+$3JG]"0Xt>Ԏw1`(J&n.lƖ-vlmDZA!]~RG6p󅛯m|Ojt<K=hʉ-ȒH~P _ƵBެ/LV)ڨWDh&X9_ao{T"TzR-w _zgBâBak:UM 6H85&"-J8oOH(hm מ&nx*?jIyPŁ^i=@^7~ y#p?`@Oe,'`;~x| Ϯg:lZvS^\\dLa y;Cɱ]PLUI!Æoʦ@R6 %g_+e۸CY0-JIRc?-עmEnw:1)o` wI#]}CtɡR;cCƊ%%۷%H/O{ 4Am<4 6Bߣ~ !!l08cTؤԑi0}!3[F14 %]6{ꉣ 5; :a_p.֛ +5`kdty{o! Fb42DmTASLWR3…ђnWm20+o XWW"M19nTR+ m"ʎsμG0lG:Yi"pĚPљصDmO1Ye0.IG)K (ٲ'?Ix~gZ a ytoY0Z`G)F5X9U fUT1'+6fC >W%f Gawӏ?G\~q3J.] Y#葰ruT/ BdKbzi1egk-ϝ=HӳH'S$Gm'AnАq+=HnhMr..!>A@3zòP49c[O>4fmѝVv'%yLjM[<~KU˶ha|ssb b՚dk;V$4|s<3'|꩓: pWD鞛ߩG'ْADz෠D=@堕/ꓯc0 !e"L=dLꗽ;wvv Eo2s/IH92*d!tC(ǹ`'k:sDHH!c{d]薔qdtS*(ԯ|4I]+f;cۖg,ԺDXLb 5{b]e_=KUb[!ni[mi'׏Ĕ%lJkBnJLJL,> dMܵt1ȣeƮ)G$ry@Li豃˫wl+05mˏ CtL2,=,+l G!fE:S[AZqY^$$>1wu_ d&+n9.1 wRȢy LTTu  V7}ᄉ]E I zb ٮ"EP^A>!ONF7G|+vhN"H~%SBW|ڪv;{GuTTZDkXKhiHp湓?xY3bDHxeFKx]F`ee"HxYH. :eXE!θ_<8ԱS.KR DyG_̓ǰ(/흛kք>Ƌ/sgO#fTi`7od{$27ϽsX)s*7 b{}+ t*9 qafj"r5퍌 P ֙tIqiq]WY-˴BrVJ}N~y$&QD)A]S{G'sBU9dJ~ R2^Е^ekР h-Wscc[sCULbYq Mc)zXzr+h^Ac $` ^LUA_J<H}WDR֖^L$ñKG M2N-$0]^QR 1:I; G*KD[W!7KiRn8we5lڥCCjDIH)̇KYpe ]ۼ͹ţǕs>Ȃ~ڕ[\|ڤGTNx j~ֽW^~Q$BDLɀx1`٦s/k{C{ 7|XFwpR0*XD <=9H R`͌+`ae,EZǧźXQ+ʑ$źu\՛YcD*i:$p$7/ '"_T*!YPu-e|UT_,m{ac z~~. U %)CWM^RhV@~dSVaY!1$>L" xO !N"}͔ahAeK;w00d*Aoy/E\%VRwՏҜ8i2 {r*"="$X.b BA^^::!=3m voh$|hN%Qi'CW^ Y$TgD(ZyUY%Vd얬O  :+lBz J!1[0N;/߶ywpU7~ݺV;e"Q~SOQʙve:V @%4٥<,If2+R?wF/vySnj㯿`}?qsN7$ bzZh/6GeP>(َta0@9sǼ.ji:_d9$h6.A a<+>"wɸPz̓ղ缛~fDsRw J]2h,f JɜS_R[F$1joWث$)ae$M |X7tȠCj؈RAXVuum{[Á,4G8܉{MUE$m=^J;}dQ-2Oh`vC8sp=I|hvH*$%t( TV[3RYĎ{ S !Ɩ<>4RQ$K)[G E ` pI-i[OdB܉^t9g^zyѫ+'N e,u n[ԏ' ŷkԚOI$\?؉J 35PE6>g_ Q2bv d>ʓOg荕7ͽ'\gV:SǕŞ[EI/v )S\Onyu=9F2!B#\"9ĖɐY{8 0> 'r,-%z1QMA0^ 7ECk v'N8,F$FG˾VJU$25&YwWR\8``RMdaj홗_^O_hsM fWN|ڊnkxw$#FȤclP$hU#G 2Y̆֍Zc;52dJ1Һ=mO<,1ĺkX}  pja)! OV}btgAc~Jkꚤ`^wu^taDcRo<*|?ϨK$lW+66LM1% d6lv}$`yjc˲e[mifso$c;^HD3zww1q%*4GYIF%(W5ԁ =>Aq%y_'PNV$> 4cU-p(K YnIoPiCۉK<';?vUvdXpdnC颒EnrȞʹKJ(`Jhפd QZnW'I6ne2 um"bZz^[W?6u{ӌQF_p;jzޢ VkRDAxX;\g}i][NG)T%L0ۣϸhDI?&m5|tHfMEVM> ]C!D;:R1e&c2ʙgcml #`yuy.錄'"(2j@7 s̍_ 9m\baXmpmT Ie7ݲsku8µSrRQ;9^6 ZDFt.8@ `i£ԣ1il72IkID ׍#Jhp]Kw 活n~t艳̨o>z]ܕSTxJ%KE kZRol׾ |+>9>ɰQ/x ѫr/w͔; M43iѝ{4`6 kh,0l%`lt iζ֝;bpʹPoݒd~b].-}/d(BvaTT,'~\vbXuQq.W^64?.|)廿lŤe˖fd.`]/dݺ@É~%S+'eH^,G*6ׯcSOF&lȋ̟6}C|#24qPIvddw2%--%&&ϐD1r=rTمs뉧w̻pσ9U{'ꉻHmwbffn33=Iw*VFI?v YSLnfteI\s;"ž"[mIG:lNI9nKB#v7w]R0CP3хR8QI\H Չçv2>v.}F! i9pWPYb玝4_ߺÏf5L6Ca^2#@K2Gi/g_îݻ5MYYY,.˩.ڞH4>̬l\bM}3u#2GIMQ-qUj 3cn4z(kbǖ_PcIXUP r g4%YƕON´n⳴nV^^]`ȝl4gJddž_{('-sEfegZG:{,cp4K+c7=_qIMGg nDhy&H6ncEf[:MRS\l&m P|,~=thqqI.mCX#vuD۲t%f5wd#9Ȁ_|ċX曪AXn4![Jr h>~)|q}kq-}ݱB\ޜ_蕦,a"p`oBC*g=sHFP4$94Aհ{v;zRFg$Z-$XnWUU]YIIfnwvuu7m)wvqH0F,qChY&xj!̿L 63Muqig v(Rܑ7o~%}ܒQ;ov!Snn%s!,'T,3umE%ERIęc<ko .w !""TY%Gr$驲#Gr!e#*JE!Y rtRV˗XvU;mhnG" MA1ww3]E%EW]T8sqiBDQgEZY[hmFꎴfgĜd˶lgǹi -;VJt[-"[[F ¤N xLn!Fiwԓ8gya8r!rti/d ޛa 5SlYWĔ[kiKg"]oܽmm-e1GSEw7郓S '6sR( me5W\8g,!58S+9XBwI#V-xO JoIw7KΫ]u#p:>uGjw_ԸA\:& H#/q.5DiCIn0oX>  4GI .M͍`b<mr%eW2W6Fib1ㆊ%޴g#thM2]h[^֔sJr D 4(+D+ јxb ƹ&_ddO1?ȳuySm4Ɋpwr: 2Ɉyk;+6޷:q JrFFL@k}D1[2^CpM 2pXhF8Lp0 LD?x *U^ZjWgMN3d MxZpȬ)=fܰa#˗^QyX3-g~vp[PV|̄^Y3]dFWY#7N{[lTcJп=1H{ܲh65kÓTrQd"vtҖsIXln$`nS# fj=ےsU ^f U,FNm1d{s%y/͙;F_-DcTMB١-843n(aaN}eou[EUvH)Mt,|Tt `rb>ꤞ\qEW\da?'N,sEA$$Pt($+L#ZIvd1cEcRr[y<Vc6XUAMVgf OaIхIdvIS?ReHDLd͢4ihL͔Apz冀EFQ ~v1'4'#P`X*VD6SWKC"K1VTH.&Gf"D_c=ǗQp΂8r2mYl֜Wz=̙cb#*z6Ҩ+x:]6Yex=(9âj5R:iM iEXh4 O]W9w܉eOJ-eh*HAbv(-֟|?8 ;;z vEfd'a k]nE*'OKY٫D*sY;XU1EO.\~nxHvAFE=g#=t ĴV1HjOȄïYMDhŁ}Ɂ)κp\~A֏~j[G[xR|l=MT-X5z\%K+W\) %`WΆ`p@ /^۷8<,n58@8bDUlΒMl$u6wwϝ?D=u݁(#@OJU `{Fl̂l 9cr][(%H,=ˇ e:i.K5V,//-ii$wtw" 4] t12}nƓ&j&|Bc(DA70K GM32-.W Pi}a‚J^Ry͗/^r![`^0@V-Q(1]BlԩJJpI"g Ll+"2DNZe#G/d'\;r$S*`D-ia=hy F RIw,>@a;6 J.Wϝ?łC/k|>K tJ[>] @wq~A*sWn))Υi7|*ҍK_Ro?ǫhnii׍Ob/)s!p0aӼfDc.7+gutuva>nE\=r,Z\͘5OY++3y8Mev[XSmo;'RD064_=tX#LYIb`O 1X{t)hx^2,x oG۰ҋ{30e$"= ulTH QRPC4ܐhɥ[}<.=X+HAԋ[o᩿™(cY̡$0!p!콰Ȏ>`Z&S/j7s4lo4ՇdGh}gLOߐj7$ D:=n5K ~eHr]R|c3[PmW1~w ̝a19Lha /Z;+?gMw=fwP]'g,=L>sҡvmI5 .+;W^^§y:E%3!sM \)b[3g猙=oO `Ǯ@Ż].5v SF e%\ &`p6cUsں#;vR-/WZ6x̘CG r:z "W˙ 7]^Y7[0iQwH!Iu;-p"%R-V,.μ0=_=@Ws^ }\}Wٹm_uumPOJtȄcR eDעnNnPh'}*mAcL)?6AIRO]a&t/> f]nr3D7H -fyLc/e b0tOl&4Oѩ?ipILKn❴#*~>7Ak瓊?9yxӞ^++N 5WQ{H8CNO 3He-\ZLO=={vmPI;d3JYh .1TJ- ?|롔z:\̼\{ i?cxˇWVBCƳKQ*% 5}q,{EżrM+u3?caI)Y,EY8ї2g,Z4Qc<~ӿK' :^ Z R O{y^ Pq6-ˉ%K npvC S<V/ІdԔ½ Tޡ}mqPZ!$ӯeO=#HgmNg>iM0{{-̾~4u [Zj\vC>cR"43vgBͿ?]n0vPsFV*>8+/b$&SڦpԔ ' mjlkSg/-͓{ߟi~k2<ޛ4tL)EuIa'mA~G;F\& Q8r;z0 oYGOqC?+;unE IDAT 7,a8S0?ĭpGJ`ې!W<ۼ[S+4dε-cO9_}.{ |v$eL/c8>~?.I`AA}P|9{ޜ/zHcS[wQ@&MfJcNE8m1҃Gl|Ι /v"qܩoYo=q̨@Y.dGsJw04T&Hm$ +GkPU |*hHuH״.-K+Ik'9|1 ZY짆!~":%B\k!///EC!774 8Ƕ:kQ@ m];M̺a .xϿ^2+ l"Гa@=}<& o1rh0?t<J5Бzpc$4 7/4flZ`5ioΎV-+`si7t_iihjޅ*KK(="$#A@~ls=/xD}lZeEobL" pؔa\9yzBw!E$RpOW8Ħ([9Z<P9n4ÒV#s$9mIOLTeQTZa;f9.#s<QSV>mGܝlڹlݼ,;fb٭w^Ks֓f4r3S:rׯ |FPh+@=Ox}ۉ#~iTA<^Bm$U?Flaw~Qcʈѓ ZE<߯RUf‘Hƽo tfevXs);EG k|% ig8adR r.!jc>F$Ѿ#|}ҁn](RG)$S$n(48=H84,d#<ФW%캺{㚫Vͦw$osbsD1Q+ 9^]S{:RQC~4Q#ʆHJ$Bt$@@T& O׃0FYܖݽqޗ^P%[M1_Rlqz,CZ`ʒesK\@[ǨS}%!|"d:&m==Nڸk\NKlrUkCXN%W.Ȑr!9XM$&oN`<28b꩏a%Lo;~277sM͔SR:`_Nn&U Oә'TAj>ݧw[|:N0fL.6} 7+-4nLdJ$ya[ \k{,[Nճ^EnXIۓ€zo8%A'ao۾hg۱!Z'J-ȶ)jMb@%bZ8e Gk{j! MY%Ń.#ZI|"yLWn񯹵PC[;jP!,8ĖRǀG *41?IH0vCݺzc~XϓzvGtcN[is 9x҄f6,;%Dz.>N',h>UO[ROFʴ$JH(*nDCGck;?PC9F쑣G /`x1ER+UzH0>Oԓʒ6`Y)CI9ùiQ7ܝks'𜼄XDsz$h].ں؉>e>-kr[}bJw=c%/Pp&ZЯfa@CT ???L) RQ"Rne%E~u}vڵԛd20 PIsIlIENDB`floodlight-0.90/src/main/resources/web/tpl/0000775000175000017500000000000012041336206021347 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/tpl/header.html0000664000175000017500000000220312041336206023462 0ustar jamespagejamespage floodlight-0.90/src/main/resources/web/tpl/port-list-item.html0000664000175000017500000000036412041336206025131 0ustar jamespagejamespage <%= name %><%= status %><%= transmitBytes %><%= receiveBytes %><%= transmitPackets %><%= receivePackets %><%= dropped %><%= errors %> floodlight-0.90/src/main/resources/web/tpl/switch-list-item.html0000664000175000017500000000034312041336206025443 0ustar jamespagejamespage <%= id %><%= inetAddress %><%= manufacturerDescription %><%= packetCount %><%= byteCount %><%= flowCount %><%= connectedSince %> floodlight-0.90/src/main/resources/web/tpl/host.html0000664000175000017500000000041212041336206023207 0ustar jamespagejamespage

IP addresses: <%= ipv4 %>
Attachment points: <%= swport %>
Last seen: <%= lastSeen %>

floodlight-0.90/src/main/resources/web/tpl/switch.html0000664000175000017500000000064512041336206023543 0ustar jamespagejamespage

Connected since <%= connectedSince %>
<%= manufacturerDescription %>
<%= hardwareDescription %>
<%= softwareDescription %>
S/N: <%= serialNumber %>

floodlight-0.90/src/main/resources/web/tpl/home.html0000664000175000017500000000020312041336206023160 0ustar jamespagejamespage
floodlight-0.90/src/main/resources/web/tpl/flow-list-item.html0000664000175000017500000000033412041336206025111 0ustar jamespagejamespage <%= cookie %><%= priority %><%= matchHTML %><%= actionText %><%= packetCount %><%= byteCount %><%= durationSeconds %> s<%= idleTimeout %> s floodlight-0.90/src/main/resources/web/tpl/status.html0000664000175000017500000000101112041336206023551 0ustar jamespagejamespage
floodlight-0.90/src/main/resources/web/tpl/host-list.html0000664000175000017500000000121412041336206024161 0ustar jamespagejamespage
Hostname:<%= host %>:<%= ofport %>
Healthy:<%= healthy %>
Uptime:<%= uptime %>
JVM memory bloat:<%= free %> free out of <%= total %>
Modules loaded:<%= moduleText %>
MAC AddressIP AddressSwitch PortLast Seen
floodlight-0.90/src/main/resources/web/tpl/vlan-list-item.html0000664000175000017500000000015412041336206025102 0ustar jamespagejamespage <%= id %><%= name %><%= nhosts %> floodlight-0.90/src/main/resources/web/tpl/topology.html0000664000175000017500000000022412041336206024107 0ustar jamespagejamespage
floodlight-0.90/src/main/resources/web/tpl/flow-list.html0000664000175000017500000000114212041336206024153 0ustar jamespagejamespage
CookiePriorityMatchActionPacketsBytesAgeTimeout
floodlight-0.90/src/main/resources/web/tpl/vlan.html0000664000175000017500000000006612041336206023177 0ustar jamespagejamespage

A VLAN probably has a list of ports and hosts.

floodlight-0.90/src/main/resources/web/tpl/port-list.html0000664000175000017500000000115012041336206024167 0ustar jamespagejamespage
#Link StatusTX BytesRX BytesTX PktsRX PktsDroppedErrors
floodlight-0.90/src/main/resources/web/tpl/host-list-item.html0000664000175000017500000000023212041336206025114 0ustar jamespagejamespage <%= mac %><%= ipv4 %><%= swport %><%= lastSeen %> floodlight-0.90/src/main/resources/web/tpl/switch-list.html0000664000175000017500000000123512041336206024510 0ustar jamespagejamespage
DPIDIP AddressVendorPacketsBytesFlowsConnected Since
floodlight-0.90/src/main/resources/web/css/0000775000175000017500000000000012041336206021340 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/css/styles.css0000664000175000017500000000026512041336206023400 0ustar jamespagejamespage.dropdown-menu { max-height: 400px; overflow-y: scroll; width: 220px; } .list-item { padding-top: 6px; padding-left: 56px; } .no-reports { display: none; }floodlight-0.90/src/main/resources/web/css/bootstrap.css0000664000175000017500000026523612041336206024105 0ustar jamespagejamespage/*! * Bootstrap v2.0.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } audio:not([controls]) { display: none; } html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } a:hover, a:active { outline: 0; } sub, sup { position: relative; font-size: 75%; line-height: 0; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { height: auto; border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } button, input, select, textarea { margin: 0; font-size: 100%; vertical-align: middle; } button, input { *overflow: visible; line-height: normal; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } input[type="search"] { -webkit-appearance: textfield; -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; } input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; } textarea { overflow: auto; vertical-align: top; } .clearfix { *zoom: 1; } .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both; } .hide-text { overflow: hidden; text-indent: 100%; white-space: nowrap; } .input-block-level { display: block; width: 100%; min-height: 28px; /* Make inputs at least the height of their button counterpart */ /* Makes inputs behave like true block-level elements */ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; } body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px; color: #0c028; /* #333333 */ background-color: white; /* #ffffff; */ } a { color: #0088cc; text-decoration: none; } a:hover { color: #005580; text-decoration: underline; } .row { margin-left: -20px; margin-top: 5px; *zoom: 1; } .row:before, .row:after { display: table; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; margin-left: 20px; } .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .span12 { width: 940px; } .span11 { width: 860px; } .span10 { width: 780px; } .span9 { width: 700px; } .span8 { width: 620px; } .span7 { width: 540px; } .span6 { width: 460px; } .span5 { width: 380px; } .span4 { width: 300px; } .span3 { width: 220px; } .span2 { width: 140px; } .span1 { width: 60px; } .offset12 { margin-left: 980px; } .offset11 { margin-left: 900px; } .offset10 { margin-left: 820px; } .offset9 { margin-left: 740px; } .offset8 { margin-left: 660px; } .offset7 { margin-left: 580px; } .offset6 { margin-left: 500px; } .offset5 { margin-left: 420px; } .offset4 { margin-left: 340px; } .offset3 { margin-left: 260px; } .offset2 { margin-left: 180px; } .offset1 { margin-left: 100px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; content: ""; } .row-fluid:after { clear: both; } .row-fluid > [class*="span"] { float: left; margin-left: 2.127659574%; } .row-fluid > [class*="span"]:first-child { margin-left: 0; } .row-fluid > .span12 { width: 99.99999998999999%; } .row-fluid > .span11 { width: 91.489361693%; } .row-fluid > .span10 { width: 82.97872339599999%; } .row-fluid > .span9 { width: 74.468085099%; } .row-fluid > .span8 { width: 65.95744680199999%; } .row-fluid > .span7 { width: 57.446808505%; } .row-fluid > .span6 { width: 48.93617020799999%; } .row-fluid > .span5 { width: 40.425531911%; } .row-fluid > .span4 { width: 31.914893614%; } .row-fluid > .span3 { width: 23.404255317%; } .row-fluid > .span2 { width: 14.89361702%; } .row-fluid > .span1 { width: 6.382978723%; } .container { margin-left: auto; margin-right: auto; *zoom: 1; } .container:before, .container:after { display: table; content: ""; } .container:after { clear: both; } .container-fluid { padding-left: 20px; padding-right: 20px; *zoom: 1; } .container-fluid:before, .container-fluid:after { display: table; content: ""; } .container-fluid:after { clear: both; } p { margin: 0 0 9px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; line-height: 18px; } p small { font-size: 11px; color: #999999; } .lead { margin-bottom: 18px; font-size: 20px; font-weight: 200; line-height: 27px; } h1, h2, h3, h4, h5, h6 { margin: 0; font-family: inherit; font-weight: bold; color: inherit; text-rendering: optimizelegibility; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-weight: normal; color: #999999; } h1 { font-size: 23px; line-height: 25px; } h1 small { font-size: 18px; } h2 { font-size: 18px; line-height: 22px; } h2 small { font-size: 18px; } h3 { line-height: 18px; font-size: 18px; } h3 small { font-size: 14px; } h4, h5, h6 { line-height: 16px; } h4 { font-size: 14px; } h4 small { font-size: 12px; } h5 { font-size: 12px; } h6 { font-size: 11px; color: #999999; text-transform: uppercase; } .page-header { padding-bottom: 17px; margin: 18px 0; border-bottom: 1px solid #eeeeee; } .page-header h1 { line-height: 1; } ul, ol { padding: 0; margin: 0 0 9px 25px; } ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; } ul { list-style: disc; } ol { list-style: decimal; } li { line-height: 18px; } ul.unstyled, ol.unstyled { margin-left: 0; list-style: none; } dl { margin-bottom: 18px; } dt, dd { line-height: 18px; } dt { font-weight: bold; line-height: 17px; } dd { margin-left: 9px; } .dl-horizontal dt { float: left; clear: left; width: 120px; text-align: right; } .dl-horizontal dd { margin-left: 130px; } hr { margin: 18px 0; border: 0; border-top: 1px solid #eeeeee; border-bottom: 1px solid #ffffff; } strong { font-weight: bold; } em { font-style: italic; } .muted { color: #999999; } abbr[title] { border-bottom: 1px dotted #ddd; cursor: help; } abbr.initialism { font-size: 90%; text-transform: uppercase; } blockquote { padding: 0 0 0 15px; margin: 0 0 18px; border-left: 5px solid #eeeeee; } blockquote p { margin-bottom: 0; font-size: 16px; font-weight: 300; line-height: 22.5px; } blockquote small { display: block; line-height: 18px; color: #999999; } blockquote small:before { content: '\2014 \00A0'; } blockquote.pull-right { float: right; padding-left: 0; padding-right: 15px; border-left: 0; border-right: 5px solid #eeeeee; } blockquote.pull-right p, blockquote.pull-right small { text-align: right; } q:before, q:after, blockquote:before, blockquote:after { content: ""; } address { display: block; margin-bottom: 18px; line-height: 18px; font-style: normal; } small { font-size: 100%; } cite { font-style: normal; } code, pre { padding: 0 3px 2px; font-family: Menlo, Monaco, "Courier New", monospace; font-size: 12px; color: #333333; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } code { padding: 2px 4px; color: #d14; background-color: #f7f7f9; border: 1px solid #e1e1e8; } pre { display: block; padding: 8.5px; margin: 0 0 9px; font-size: 12.025px; line-height: 18px; background-color: #f5f5f5; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; white-space: pre; white-space: pre-wrap; word-break: break-all; word-wrap: break-word; } pre.prettyprint { margin-bottom: 18px; } pre code { padding: 0; color: inherit; background-color: transparent; border: 0; } .pre-scrollable { max-height: 340px; overflow-y: scroll; } form { margin: 0 0 18px; } fieldset { padding: 0; margin: 0; border: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: 27px; font-size: 19.5px; line-height: 36px; color: #333333; border: 0; border-bottom: 1px solid #eee; } legend small { font-size: 13.5px; color: #999999; } label, input, button, select, textarea { font-size: 13px; font-weight: normal; line-height: 18px; } input, button, select, textarea { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } label { display: block; margin-bottom: 5px; color: #333333; } input, textarea, select, .uneditable-input { display: inline-block; width: 210px; height: 18px; padding: 4px; margin-bottom: 9px; font-size: 13px; line-height: 18px; color: #555555; border: 1px solid #cccccc; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .uneditable-textarea { width: auto; height: auto; } label input, label textarea, label select { display: block; } input[type="image"], input[type="checkbox"], input[type="radio"] { width: auto; height: auto; padding: 0; margin: 3px 0; *margin-top: 0; /* IE7 */ line-height: normal; cursor: pointer; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; border: 0 \9; /* IE9 and down */ } input[type="image"] { border: 0; } input[type="file"] { width: auto; padding: initial; line-height: initial; border: initial; background-color: #ffffff; background-color: initial; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } input[type="button"], input[type="reset"], input[type="submit"] { width: auto; height: auto; } select, input[type="file"] { height: 28px; /* In IE7, the height of the select element cannot be changed by height, only font-size */ *margin-top: 4px; /* For IE7, add top margin to align select with labels */ line-height: 28px; } input[type="file"] { line-height: 18px \9; } select { width: 220px; background-color: #ffffff; } select[multiple], select[size] { height: auto; } input[type="image"] { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } textarea { height: auto; } input[type="hidden"] { display: none; } .radio, .checkbox { padding-left: 18px; } .radio input[type="radio"], .checkbox input[type="checkbox"] { float: left; margin-left: -18px; } .controls > .radio:first-child, .controls > .checkbox:first-child { padding-top: 5px; } .radio.inline, .checkbox.inline { display: inline-block; padding-top: 5px; margin-bottom: 0; vertical-align: middle; } .radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { margin-left: 10px; } input, textarea { -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -ms-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; } input:focus, textarea:focus { border-color: rgba(82, 168, 236, 0.8); -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); outline: 0; outline: thin dotted \9; /* IE6-9 */ } input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus, select:focus { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .input-mini { width: 60px; } .input-small { width: 90px; } .input-medium { width: 150px; } .input-large { width: 210px; } .input-xlarge { width: 270px; } .input-xxlarge { width: 530px; } input[class*="span"], select[class*="span"], textarea[class*="span"], .uneditable-input { float: none; margin-left: 0; } input, textarea, .uneditable-input { margin-left: 0; } input.span12, textarea.span12, .uneditable-input.span12 { width: 930px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 850px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 770px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 690px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 610px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 530px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 450px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 370px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 290px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 210px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 130px; } input.span1, textarea.span1, .uneditable-input.span1 { width: 50px; } input[disabled], select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { background-color: #eeeeee; border-color: #ddd; cursor: not-allowed; } .control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { color: #c09853; } .control-group.warning input, .control-group.warning select, .control-group.warning textarea { color: #c09853; border-color: #c09853; } .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { border-color: #a47e3c; -webkit-box-shadow: 0 0 6px #dbc59e; -moz-box-shadow: 0 0 6px #dbc59e; box-shadow: 0 0 6px #dbc59e; } .control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { color: #c09853; background-color: #fcf8e3; border-color: #c09853; } .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { color: #b94a48; } .control-group.error input, .control-group.error select, .control-group.error textarea { color: #b94a48; border-color: #b94a48; } .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { border-color: #953b39; -webkit-box-shadow: 0 0 6px #d59392; -moz-box-shadow: 0 0 6px #d59392; box-shadow: 0 0 6px #d59392; } .control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { color: #b94a48; background-color: #f2dede; border-color: #b94a48; } .control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { color: #468847; } .control-group.success input, .control-group.success select, .control-group.success textarea { color: #468847; border-color: #468847; } .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { border-color: #356635; -webkit-box-shadow: 0 0 6px #7aba7b; -moz-box-shadow: 0 0 6px #7aba7b; box-shadow: 0 0 6px #7aba7b; } .control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { color: #468847; background-color: #dff0d8; border-color: #468847; } input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { color: #b94a48; border-color: #ee5f5b; } input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { border-color: #e9322d; -webkit-box-shadow: 0 0 6px #f8b9b7; -moz-box-shadow: 0 0 6px #f8b9b7; box-shadow: 0 0 6px #f8b9b7; } .form-actions { padding: 17px 20px 18px; margin-top: 18px; margin-bottom: 18px; background-color: #eeeeee; border-top: 1px solid #ddd; *zoom: 1; } .form-actions:before, .form-actions:after { display: table; content: ""; } .form-actions:after { clear: both; } .uneditable-input { display: block; background-color: #ffffff; border-color: #eee; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); cursor: not-allowed; } :-moz-placeholder { color: #999999; } ::-webkit-input-placeholder { color: #999999; } .help-block, .help-inline { color: #555555; } .help-block { display: block; margin-bottom: 9px; } .help-inline { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; vertical-align: middle; padding-left: 5px; } .input-prepend, .input-append { margin-bottom: 5px; } .input-prepend input, .input-append input, .input-prepend select, .input-append select, .input-prepend .uneditable-input, .input-append .uneditable-input { *margin-left: 0; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-prepend input:focus, .input-append input:focus, .input-prepend select:focus, .input-append select:focus, .input-prepend .uneditable-input:focus, .input-append .uneditable-input:focus { position: relative; z-index: 2; } .input-prepend .uneditable-input, .input-append .uneditable-input { border-left-color: #ccc; } .input-prepend .add-on, .input-append .add-on { display: inline-block; width: auto; min-width: 16px; height: 18px; padding: 4px 5px; font-weight: normal; line-height: 18px; text-align: center; text-shadow: 0 1px 0 #ffffff; vertical-align: middle; background-color: #eeeeee; border: 1px solid #ccc; } .input-prepend .add-on, .input-append .add-on, .input-prepend .btn, .input-append .btn { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-prepend .active, .input-append .active { background-color: #a9dba9; border-color: #46a546; } .input-prepend .add-on, .input-prepend .btn { margin-right: -1px; } .input-append input, .input-append select .uneditable-input { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-append .uneditable-input { border-left-color: #eee; border-right-color: #ccc; } .input-append .add-on, .input-append .btn { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-prepend.input-append input, .input-prepend.input-append select, .input-prepend.input-append .uneditable-input { -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .input-prepend.input-append .add-on:first-child, .input-prepend.input-append .btn:first-child { margin-right: -1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-prepend.input-append .add-on:last-child, .input-prepend.input-append .btn:last-child { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .search-query { padding-left: 14px; padding-right: 14px; margin-bottom: 0; -webkit-border-radius: 14px; -moz-border-radius: 14px; border-radius: 14px; } .form-search input, .form-inline input, .form-horizontal input, .form-search textarea, .form-inline textarea, .form-horizontal textarea, .form-search select, .form-inline select, .form-horizontal select, .form-search .help-inline, .form-inline .help-inline, .form-horizontal .help-inline, .form-search .uneditable-input, .form-inline .uneditable-input, .form-horizontal .uneditable-input, .form-search .input-prepend, .form-inline .input-prepend, .form-horizontal .input-prepend, .form-search .input-append, .form-inline .input-append, .form-horizontal .input-append { display: inline-block; margin-bottom: 0; } .form-search .hide, .form-inline .hide, .form-horizontal .hide { display: none; } .form-search label, .form-inline label { display: inline-block; } .form-search .input-append, .form-inline .input-append, .form-search .input-prepend, .form-inline .input-prepend { margin-bottom: 0; } .form-search .radio, .form-search .checkbox, .form-inline .radio, .form-inline .checkbox { padding-left: 0; margin-bottom: 0; vertical-align: middle; } .form-search .radio input[type="radio"], .form-search .checkbox input[type="checkbox"], .form-inline .radio input[type="radio"], .form-inline .checkbox input[type="checkbox"] { float: left; margin-left: 0; margin-right: 3px; } .control-group { margin-bottom: 9px; } legend + .control-group { margin-top: 18px; -webkit-margin-top-collapse: separate; } .form-horizontal .control-group { margin-bottom: 18px; *zoom: 1; } .form-horizontal .control-group:before, .form-horizontal .control-group:after { display: table; content: ""; } .form-horizontal .control-group:after { clear: both; } .form-horizontal .control-label { float: left; width: 140px; padding-top: 5px; text-align: right; } .form-horizontal .controls { margin-left: 160px; /* Super jank IE7 fix to ensure the inputs in .input-append and input-prepend don't inherit the margin of the parent, in this case .controls */ *display: inline-block; *margin-left: 0; *padding-left: 20px; } .form-horizontal .help-block { margin-top: 9px; margin-bottom: 0; } .form-horizontal .form-actions { padding-left: 160px; } table { max-width: 100%; border-collapse: collapse; border-spacing: 0; background-color: transparent; } .table { width: 100%; margin-bottom: 18px; } .table th, .table td { padding: 8px; line-height: 18px; text-align: left; vertical-align: top; border-top: 1px solid #dddddd; } .table th { font-weight: bold; } .table thead th { vertical-align: bottom; } .table colgroup + thead tr:first-child th, .table colgroup + thead tr:first-child td, .table thead:first-child tr:first-child th, .table thead:first-child tr:first-child td { border-top: 0; } .table tbody + tbody { border-top: 2px solid #dddddd; } .table-condensed th, .table-condensed td { padding: 4px 5px; } .table-bordered { border: 1px solid #dddddd; border-left: 0; border-collapse: separate; *border-collapse: collapsed; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .table-bordered th, .table-bordered td { border-left: 1px solid #dddddd; } .table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { border-top: 0; } .table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { -webkit-border-radius: 4px 0 0 0; -moz-border-radius: 4px 0 0 0; border-radius: 4px 0 0 0; } .table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { -webkit-border-radius: 0 4px 0 0; -moz-border-radius: 0 4px 0 0; border-radius: 0 4px 0 0; } .table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { -webkit-border-radius: 0 0 0 4px; -moz-border-radius: 0 0 0 4px; border-radius: 0 0 0 4px; } .table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { -webkit-border-radius: 0 0 4px 0; -moz-border-radius: 0 0 4px 0; border-radius: 0 0 4px 0; } .table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { background-color: #f9f9f9; } .table tbody tr:hover td, .table tbody tr:hover th { background-color: #f5f5f5; } table .span1 { float: none; width: 44px; margin-left: 0; } table .span2 { float: none; width: 124px; margin-left: 0; } table .span3 { float: none; width: 204px; margin-left: 0; } table .span4 { float: none; width: 284px; margin-left: 0; } table .span5 { float: none; width: 364px; margin-left: 0; } table .span6 { float: none; width: 444px; margin-left: 0; } table .span7 { float: none; width: 524px; margin-left: 0; } table .span8 { float: none; width: 604px; margin-left: 0; } table .span9 { float: none; width: 684px; margin-left: 0; } table .span10 { float: none; width: 764px; margin-left: 0; } table .span11 { float: none; width: 844px; margin-left: 0; } table .span12 { float: none; width: 924px; margin-left: 0; } table .span13 { float: none; width: 1004px; margin-left: 0; } table .span14 { float: none; width: 1084px; margin-left: 0; } table .span15 { float: none; width: 1164px; margin-left: 0; } table .span16 { float: none; width: 1244px; margin-left: 0; } table .span17 { float: none; width: 1324px; margin-left: 0; } table .span18 { float: none; width: 1404px; margin-left: 0; } table .span19 { float: none; width: 1484px; margin-left: 0; } table .span20 { float: none; width: 1564px; margin-left: 0; } table .span21 { float: none; width: 1644px; margin-left: 0; } table .span22 { float: none; width: 1724px; margin-left: 0; } table .span23 { float: none; width: 1804px; margin-left: 0; } table .span24 { float: none; width: 1884px; margin-left: 0; } [class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; line-height: 14px; vertical-align: text-top; background-image: url("../img/glyphicons-halflings.png"); background-position: 14px 14px; background-repeat: no-repeat; *margin-right: .3em; } [class^="icon-"]:last-child, [class*=" icon-"]:last-child { *margin-left: 0; } .icon-white { background-image: url("../img/glyphicons-halflings-white.png"); } .icon-glass { background-position: 0 0; } .icon-music { background-position: -24px 0; } .icon-search { background-position: -48px 0; } .icon-envelope { background-position: -72px 0; } .icon-heart { background-position: -96px 0; } .icon-star { background-position: -120px 0; } .icon-star-empty { background-position: -144px 0; } .icon-user { background-position: -168px 0; } .icon-film { background-position: -192px 0; } .icon-th-large { background-position: -216px 0; } .icon-th { background-position: -240px 0; } .icon-th-list { background-position: -264px 0; } .icon-ok { background-position: -288px 0; } .icon-remove { background-position: -312px 0; } .icon-zoom-in { background-position: -336px 0; } .icon-zoom-out { background-position: -360px 0; } .icon-off { background-position: -384px 0; } .icon-signal { background-position: -408px 0; } .icon-cog { background-position: -432px 0; } .icon-trash { background-position: -456px 0; } .icon-home { background-position: 0 -24px; } .icon-file { background-position: -24px -24px; } .icon-time { background-position: -48px -24px; } .icon-road { background-position: -72px -24px; } .icon-download-alt { background-position: -96px -24px; } .icon-download { background-position: -120px -24px; } .icon-upload { background-position: -144px -24px; } .icon-inbox { background-position: -168px -24px; } .icon-play-circle { background-position: -192px -24px; } .icon-repeat { background-position: -216px -24px; } .icon-refresh { background-position: -240px -24px; } .icon-list-alt { background-position: -264px -24px; } .icon-lock { background-position: -287px -24px; } .icon-flag { background-position: -312px -24px; } .icon-headphones { background-position: -336px -24px; } .icon-volume-off { background-position: -360px -24px; } .icon-volume-down { background-position: -384px -24px; } .icon-volume-up { background-position: -408px -24px; } .icon-qrcode { background-position: -432px -24px; } .icon-barcode { background-position: -456px -24px; } .icon-tag { background-position: 0 -48px; } .icon-tags { background-position: -25px -48px; } .icon-book { background-position: -48px -48px; } .icon-bookmark { background-position: -72px -48px; } .icon-print { background-position: -96px -48px; } .icon-camera { background-position: -120px -48px; } .icon-font { background-position: -144px -48px; } .icon-bold { background-position: -167px -48px; } .icon-italic { background-position: -192px -48px; } .icon-text-height { background-position: -216px -48px; } .icon-text-width { background-position: -240px -48px; } .icon-align-left { background-position: -264px -48px; } .icon-align-center { background-position: -288px -48px; } .icon-align-right { background-position: -312px -48px; } .icon-align-justify { background-position: -336px -48px; } .icon-list { background-position: -360px -48px; } .icon-indent-left { background-position: -384px -48px; } .icon-indent-right { background-position: -408px -48px; } .icon-facetime-video { background-position: -432px -48px; } .icon-picture { background-position: -456px -48px; } .icon-pencil { background-position: 0 -72px; } .icon-map-marker { background-position: -24px -72px; } .icon-adjust { background-position: -48px -72px; } .icon-tint { background-position: -72px -72px; } .icon-edit { background-position: -96px -72px; } .icon-share { background-position: -120px -72px; } .icon-check { background-position: -144px -72px; } .icon-move { background-position: -168px -72px; } .icon-step-backward { background-position: -192px -72px; } .icon-fast-backward { background-position: -216px -72px; } .icon-backward { background-position: -240px -72px; } .icon-play { background-position: -264px -72px; } .icon-pause { background-position: -288px -72px; } .icon-stop { background-position: -312px -72px; } .icon-forward { background-position: -336px -72px; } .icon-fast-forward { background-position: -360px -72px; } .icon-step-forward { background-position: -384px -72px; } .icon-eject { background-position: -408px -72px; } .icon-chevron-left { background-position: -432px -72px; } .icon-chevron-right { background-position: -456px -72px; } .icon-plus-sign { background-position: 0 -96px; } .icon-minus-sign { background-position: -24px -96px; } .icon-remove-sign { background-position: -48px -96px; } .icon-ok-sign { background-position: -72px -96px; } .icon-question-sign { background-position: -96px -96px; } .icon-info-sign { background-position: -120px -96px; } .icon-screenshot { background-position: -144px -96px; } .icon-remove-circle { background-position: -168px -96px; } .icon-ok-circle { background-position: -192px -96px; } .icon-ban-circle { background-position: -216px -96px; } .icon-arrow-left { background-position: -240px -96px; } .icon-arrow-right { background-position: -264px -96px; } .icon-arrow-up { background-position: -289px -96px; } .icon-arrow-down { background-position: -312px -96px; } .icon-share-alt { background-position: -336px -96px; } .icon-resize-full { background-position: -360px -96px; } .icon-resize-small { background-position: -384px -96px; } .icon-plus { background-position: -408px -96px; } .icon-minus { background-position: -433px -96px; } .icon-asterisk { background-position: -456px -96px; } .icon-exclamation-sign { background-position: 0 -120px; } .icon-gift { background-position: -24px -120px; } .icon-leaf { background-position: -48px -120px; } .icon-fire { background-position: -72px -120px; } .icon-eye-open { background-position: -96px -120px; } .icon-eye-close { background-position: -120px -120px; } .icon-warning-sign { background-position: -144px -120px; } .icon-plane { background-position: -168px -120px; } .icon-calendar { background-position: -192px -120px; } .icon-random { background-position: -216px -120px; } .icon-comment { background-position: -240px -120px; } .icon-magnet { background-position: -264px -120px; } .icon-chevron-up { background-position: -288px -120px; } .icon-chevron-down { background-position: -313px -119px; } .icon-retweet { background-position: -336px -120px; } .icon-shopping-cart { background-position: -360px -120px; } .icon-folder-close { background-position: -384px -120px; } .icon-folder-open { background-position: -408px -120px; } .icon-resize-vertical { background-position: -432px -119px; } .icon-resize-horizontal { background-position: -456px -118px; } .dropdown { position: relative; } .dropdown-toggle { *margin-bottom: -3px; } .dropdown-toggle:active, .open .dropdown-toggle { outline: 0; } .caret { display: inline-block; width: 0; height: 0; vertical-align: top; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid #000000; opacity: 0.3; filter: alpha(opacity=30); content: ""; } .dropdown .caret { margin-top: 8px; margin-left: 2px; } .dropdown:hover .caret, .open.dropdown .caret { opacity: 1; filter: alpha(opacity=100); } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; float: left; display: none; min-width: 160px; padding: 4px 0; margin: 0; list-style: none; background-color: #ffffff; border-color: #ccc; border-color: rgba(0, 0, 0, 0.2); border-style: solid; border-width: 1px; -webkit-border-radius: 0 0 5px 5px; -moz-border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; *border-right-width: 2px; *border-bottom-width: 2px; } .dropdown-menu.pull-right { right: 0; left: auto; } .dropdown-menu .divider { height: 1px; margin: 8px 1px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; *width: 100%; *margin: -5px 0 5px; } .dropdown-menu a { display: block; padding: 3px 15px; clear: both; font-weight: normal; line-height: 18px; color: #333333; white-space: nowrap; } .dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { color: #ffffff; text-decoration: none; background-color: #0088cc; } .dropdown.open { *z-index: 1000; } .dropdown.open .dropdown-toggle { color: #ffffff; background: #ccc; background: rgba(0, 0, 0, 0.3); } .dropdown.open .dropdown-menu { display: block; } .pull-right .dropdown-menu { left: auto; right: 0; } .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid #000000; content: "\2191"; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 1px; } .typeahead { margin-top: 2px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #eee; border: 1px solid rgba(0, 0, 0, 0.05); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } .well-large { padding: 24px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .well-small { padding: 9px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .fade { -webkit-transition: opacity 0.15s linear; -moz-transition: opacity 0.15s linear; -ms-transition: opacity 0.15s linear; -o-transition: opacity 0.15s linear; transition: opacity 0.15s linear; opacity: 0; } .fade.in { opacity: 1; } .collapse { -webkit-transition: height 0.35s ease; -moz-transition: height 0.35s ease; -ms-transition: height 0.35s ease; -o-transition: height 0.35s ease; transition: height 0.35s ease; position: relative; overflow: hidden; height: 0; } .collapse.in { height: auto; } .close { float: right; font-size: 20px; font-weight: bold; line-height: 18px; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover { color: #000000; text-decoration: none; opacity: 0.4; filter: alpha(opacity=40); cursor: pointer; } .btn { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); border-color: #e6e6e6 #e6e6e6 #bfbfbf; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); border: 1px solid #cccccc; border-bottom-color: #b3b3b3; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; } .btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; } .btn:active, .btn.active { background-color: #cccccc \9; } .btn:first-child { *margin-left: 0; } .btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; } .btn:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .btn.active, .btn:active { background-image: none; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); background-color: #e6e6e6; background-color: #d9d9d9 \9; outline: 0; } .btn.disabled, .btn[disabled] { cursor: default; background-image: none; background-color: #e6e6e6; opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .btn-large [class^="icon-"] { margin-top: 1px; } .btn-small { padding: 5px 9px; font-size: 11px; line-height: 16px; } .btn-small [class^="icon-"] { margin-top: -1px; } .btn-mini { padding: 2px 6px; font-size: 11px; line-height: 14px; } .btn-primary, .btn-primary:hover, .btn-warning, .btn-warning:hover, .btn-danger, .btn-danger:hover, .btn-success, .btn-success:hover, .btn-info, .btn-info:hover, .btn-inverse, .btn-inverse:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; } .btn-primary.active, .btn-warning.active, .btn-danger.active, .btn-success.active, .btn-info.active, .btn-inverse.active { color: rgba(255, 255, 255, 0.75); } .btn-primary { background-color: #0074cc; background-image: -moz-linear-gradient(top, #0088cc, #0055cc); background-image: -ms-linear-gradient(top, #0088cc, #0055cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); background-image: -o-linear-gradient(top, #0088cc, #0055cc); background-image: linear-gradient(top, #0088cc, #0055cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); border-color: #0055cc #0055cc #003580; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { background-color: #0055cc; } .btn-primary:active, .btn-primary.active { background-color: #004099 \9; } .btn-warning { background-color: #faa732; background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -ms-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); border-color: #f89406 #f89406 #ad6704; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-warning:hover, .btn-warning:active, .btn-warning.active, .btn-warning.disabled, .btn-warning[disabled] { background-color: #f89406; } .btn-warning:active, .btn-warning.active { background-color: #c67605 \9; } .btn-danger { background-color: #da4f49; background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); background-image: linear-gradient(top, #ee5f5b, #bd362f); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); border-color: #bd362f #bd362f #802420; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-danger:hover, .btn-danger:active, .btn-danger.active, .btn-danger.disabled, .btn-danger[disabled] { background-color: #bd362f; } .btn-danger:active, .btn-danger.active { background-color: #942a25 \9; } .btn-success { background-color: #5bb75b; background-image: -moz-linear-gradient(top, #62c462, #51a351); background-image: -ms-linear-gradient(top, #62c462, #51a351); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); background-image: -webkit-linear-gradient(top, #62c462, #51a351); background-image: -o-linear-gradient(top, #62c462, #51a351); background-image: linear-gradient(top, #62c462, #51a351); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); border-color: #51a351 #51a351 #387038; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-success:hover, .btn-success:active, .btn-success.active, .btn-success.disabled, .btn-success[disabled] { background-color: #51a351; } .btn-success:active, .btn-success.active { background-color: #408140 \9; } .btn-info { background-color: #49afcd; background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); background-image: linear-gradient(top, #5bc0de, #2f96b4); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); border-color: #2f96b4 #2f96b4 #1f6377; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-info:hover, .btn-info:active, .btn-info.active, .btn-info.disabled, .btn-info[disabled] { background-color: #2f96b4; } .btn-info:active, .btn-info.active { background-color: #24748c \9; } .btn-inverse { background-color: #414141; background-image: -moz-linear-gradient(top, #555555, #222222); background-image: -ms-linear-gradient(top, #555555, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); background-image: -webkit-linear-gradient(top, #555555, #222222); background-image: -o-linear-gradient(top, #555555, #222222); background-image: linear-gradient(top, #555555, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-inverse:hover, .btn-inverse:active, .btn-inverse.active, .btn-inverse.disabled, .btn-inverse[disabled] { background-color: #222222; } .btn-inverse:active, .btn-inverse.active { background-color: #080808 \9; } button.btn, input[type="submit"].btn { *padding-top: 2px; *padding-bottom: 2px; } button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { padding: 0; border: 0; } button.btn.btn-large, input[type="submit"].btn.btn-large { *padding-top: 7px; *padding-bottom: 7px; } button.btn.btn-small, input[type="submit"].btn.btn-small { *padding-top: 3px; *padding-bottom: 3px; } button.btn.btn-mini, input[type="submit"].btn.btn-mini { *padding-top: 1px; *padding-bottom: 1px; } .btn-group { position: relative; *zoom: 1; *margin-left: .3em; } .btn-group:before, .btn-group:after { display: table; content: ""; } .btn-group:after { clear: both; } .btn-group:first-child { *margin-left: 0; } .btn-group + .btn-group { margin-left: 5px; } .btn-toolbar { margin-top: 9px; margin-bottom: 9px; } .btn-toolbar .btn-group { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; } .btn-group .btn { position: relative; float: left; margin-left: -1px; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .btn-group .btn:first-child { margin-left: 0; -webkit-border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; border-top-left-radius: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; border-bottom-left-radius: 4px; } .btn-group .btn:last-child, .btn-group .dropdown-toggle { -webkit-border-top-right-radius: 4px; -moz-border-radius-topright: 4px; border-top-right-radius: 4px; -webkit-border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; border-bottom-right-radius: 4px; } .btn-group .btn.large:first-child { margin-left: 0; -webkit-border-top-left-radius: 6px; -moz-border-radius-topleft: 6px; border-top-left-radius: 6px; -webkit-border-bottom-left-radius: 6px; -moz-border-radius-bottomleft: 6px; border-bottom-left-radius: 6px; } .btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { -webkit-border-top-right-radius: 6px; -moz-border-radius-topright: 6px; border-top-right-radius: 6px; -webkit-border-bottom-right-radius: 6px; -moz-border-radius-bottomright: 6px; border-bottom-right-radius: 6px; } .btn-group .btn:hover, .btn-group .btn:focus, .btn-group .btn:active, .btn-group .btn.active { z-index: 2; } .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } .btn-group .dropdown-toggle { padding-left: 8px; padding-right: 8px; -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); *padding-top: 3px; *padding-bottom: 3px; } .btn-group .btn-mini.dropdown-toggle { padding-left: 5px; padding-right: 5px; *padding-top: 1px; *padding-bottom: 1px; } .btn-group .btn-small.dropdown-toggle { *padding-top: 4px; *padding-bottom: 4px; } .btn-group .btn-large.dropdown-toggle { padding-left: 12px; padding-right: 12px; } .btn-group.open { *z-index: 1000; } .btn-group.open .dropdown-menu { display: block; margin-top: 1px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .btn-group.open .dropdown-toggle { background-image: none; -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn .caret { margin-top: 7px; margin-left: 0; } .btn:hover .caret, .open.btn-group .caret { opacity: 1; filter: alpha(opacity=100); } .btn-mini .caret { margin-top: 5px; } .btn-small .caret { margin-top: 6px; } .btn-large .caret { margin-top: 6px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .btn-primary .caret, .btn-warning .caret, .btn-danger .caret, .btn-info .caret, .btn-success .caret, .btn-inverse .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 0.75; filter: alpha(opacity=75); } .alert { padding: 8px 35px 8px 14px; margin-bottom: 18px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #c09853; } .alert-heading { color: inherit; } .alert .close { position: relative; top: -2px; right: -21px; line-height: 18px; } .alert-success { background-color: #dff0d8; border-color: #d6e9c6; color: #468847; } .alert-danger, .alert-error { background-color: #f2dede; border-color: #eed3d7; color: #b94a48; } .alert-info { background-color: #d9edf7; border-color: #bce8f1; color: #3a87ad; } .alert-block { padding-top: 14px; padding-bottom: 14px; } .alert-block > p, .alert-block > ul { margin-bottom: 0; } .alert-block p + p { margin-top: 5px; } .nav { margin-left: 0; margin-bottom: 18px; list-style: none; } .nav > li > a { display: block; } .nav > li > a:hover { text-decoration: none; background-color: #eeeeee; } .nav .nav-header { display: block; padding: 3px 15px; font-size: 11px; font-weight: bold; line-height: 18px; color: white; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); text-transform: uppercase; } .nav li + .nav-header { margin-top: 9px; } .nav-list { padding-left: 15px; padding-right: 15px; margin-bottom: 0; } .nav-list > li > a, .nav-list .nav-header { margin-left: -15px; margin-right: -15px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } .nav-list > li > a { padding: 3px 15px; } .nav-list > .active > a, .nav-list > .active > a:hover { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); background-color: #0088cc; } .nav-list [class^="icon-"] { margin-right: 2px; } .nav-list .divider { height: 1px; margin: 8px 1px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; *width: 100%; *margin: -5px 0 5px; } .nav-tabs, .nav-pills { *zoom: 1; } .nav-tabs:before, .nav-pills:before, .nav-tabs:after, .nav-pills:after { display: table; content: ""; } .nav-tabs:after, .nav-pills:after { clear: both; } .nav-tabs > li, .nav-pills > li { float: left; } .nav-tabs > li > a, .nav-pills > li > a { padding-right: 12px; padding-left: 12px; margin-right: 2px; line-height: 14px; } .nav-tabs { border-bottom: 1px solid #ddd; } .nav-tabs > li { margin-bottom: -1px; } .nav-tabs > li > a { padding-top: 8px; padding-bottom: 8px; line-height: 18px; border: 1px solid transparent; -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; } .nav-tabs > .active > a, .nav-tabs > .active > a:hover { color: #555555; background-color: #ffffff; border: 1px solid #ddd; border-bottom-color: transparent; cursor: default; } .nav-pills > li > a { padding-top: 8px; padding-bottom: 8px; margin-top: 2px; margin-bottom: 2px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .nav-pills > .active > a, .nav-pills > .active > a:hover { color: #ffffff; background-color: #0088cc; } .nav-stacked > li { float: none; } .nav-stacked > li > a { margin-right: 0; } .nav-tabs.nav-stacked { border-bottom: 0; } .nav-tabs.nav-stacked > li > a { border: 1px solid #ddd; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .nav-tabs.nav-stacked > li:first-child > a { -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .nav-tabs.nav-stacked > li:last-child > a { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .nav-tabs.nav-stacked > li > a:hover { border-color: #ddd; z-index: 2; } .nav-pills.nav-stacked > li > a { margin-bottom: 3px; } .nav-pills.nav-stacked > li:last-child > a { margin-bottom: 1px; } .nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { margin-top: 1px; border-width: 1px; } .nav-pills .dropdown-menu { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { border-top-color: #0088cc; border-bottom-color: #0088cc; margin-top: 6px; } .nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { border-top-color: #005580; border-bottom-color: #005580; } .nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { border-top-color: #333333; border-bottom-color: #333333; } .nav > .dropdown.active > a:hover { color: #000000; cursor: pointer; } .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { color: #ffffff; background-color: #999999; border-color: #999999; } .nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 1; filter: alpha(opacity=100); } .tabs-stacked .open > a:hover { border-color: #999999; } .tabbable { *zoom: 1; } .tabbable:before, .tabbable:after { display: table; content: ""; } .tabbable:after { clear: both; } .tab-content { display: table; width: 100%; } .tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { border-bottom: 0; } .tab-content > .tab-pane, .pill-content > .pill-pane { display: none; } .tab-content > .active, .pill-content > .active { display: block; } .tabs-below .nav-tabs { border-top: 1px solid #ddd; } .tabs-below .nav-tabs > li { margin-top: -1px; margin-bottom: 0; } .tabs-below .nav-tabs > li > a { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .tabs-below .nav-tabs > li > a:hover { border-bottom-color: transparent; border-top-color: #ddd; } .tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { border-color: transparent #ddd #ddd #ddd; } .tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { float: none; } .tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { min-width: 74px; margin-right: 0; margin-bottom: 3px; } .tabs-left .nav-tabs { float: left; margin-right: 19px; border-right: 1px solid #ddd; } .tabs-left .nav-tabs > li > a { margin-right: -1px; -webkit-border-radius: 4px 0 0 4px; -moz-border-radius: 4px 0 0 4px; border-radius: 4px 0 0 4px; } .tabs-left .nav-tabs > li > a:hover { border-color: #eeeeee #dddddd #eeeeee #eeeeee; } .tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { border-color: #ddd transparent #ddd #ddd; *border-right-color: #ffffff; } .tabs-right .nav-tabs { float: right; margin-left: 19px; border-left: 1px solid #ddd; } .tabs-right .nav-tabs > li > a { margin-left: -1px; -webkit-border-radius: 0 4px 4px 0; -moz-border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0; } .tabs-right .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #eeeeee #dddddd; } .tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { border-color: #ddd #ddd #ddd transparent; *border-left-color: #ffffff; } .navbar { *position: relative; *z-index: 2; overflow: visible; margin-bottom: 18px; } .navbar-inner { padding-left: 20px; padding-right: 20px; background-color: white; border-bottom: 2px solid #221e50; /* background-image: -moz-linear-gradient(top, #333333, #222222); background-image: -ms-linear-gradient(top, #333333, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); background-image: -webkit-linear-gradient(top, #333333, #222222); background-image: -o-linear-gradient(top, #333333, #222222); background-image: linear-gradient(top, #333333, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);*/ } .navbar .container { width: auto; } .btn-navbar { display: none; float: right; padding: 7px 10px; margin-left: 5px; margin-right: 5px; background-color: #2c2c2c; background-image: -moz-linear-gradient(top, #333333, #222222); background-image: -ms-linear-gradient(top, #333333, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); background-image: -webkit-linear-gradient(top, #333333, #222222); background-image: -o-linear-gradient(top, #333333, #222222); background-image: linear-gradient(top, #333333, #222222); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(enabled=false); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); } .btn-navbar:hover, .btn-navbar:active, .btn-navbar.active, .btn-navbar.disabled, .btn-navbar[disabled] { background-color: #222222; } .btn-navbar:active, .btn-navbar.active { background-color: #080808 \9; } .btn-navbar .icon-bar { display: block; width: 18px; height: 2px; background-color: #f5f5f5; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); } .btn-navbar .icon-bar + .icon-bar { margin-top: 3px; } .nav-collapse.collapse { height: auto; } .navbar { color: #999999; } .navbar .brand:hover { text-decoration: none; } .navbar .brand { float: left; display: block; padding: 8px 20px 12px; margin-left: -20px; font-size: 20px; font-weight: 200; line-height: 1; color: #ffffff; } .navbar .navbar-text { margin-bottom: 0; line-height: 40px; } .navbar .btn, .navbar .btn-group { margin-top: 5px; } .navbar .btn-group .btn { margin-top: 0; } .navbar-form { margin-bottom: 0; *zoom: 1; } .navbar-form:before, .navbar-form:after { display: table; content: ""; } .navbar-form:after { clear: both; } .navbar-form input, .navbar-form select, .navbar-form .radio, .navbar-form .checkbox { margin-top: 5px; } .navbar-form input, .navbar-form select { display: inline-block; margin-bottom: 0; } .navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { margin-top: 3px; } .navbar-form .input-append, .navbar-form .input-prepend { margin-top: 6px; white-space: nowrap; } .navbar-form .input-append input, .navbar-form .input-prepend input { margin-top: 0; } .navbar-search { position: relative; float: left; margin-top: 17px; margin-bottom: 0; } .navbar-search .search-query { padding: 4px 9px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: 1; color: #ffffff; background-color: #626262; border: 1px solid #151515; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none; transition: none; } .navbar-search .search-query:-moz-placeholder { color: #cccccc; } .navbar-search .search-query::-webkit-input-placeholder { color: #cccccc; } .navbar-search .search-query:focus, .navbar-search .search-query.focused { padding: 5px 10px; color: #333333; text-shadow: 0 1px 0 #ffffff; background-color: #ffffff; border: 0; -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); outline: 0; } .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; right: 0; left: 0; z-index: 1030; margin-bottom: 0; } .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner { padding-left: 0; padding-right: 0; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .navbar-fixed-top { top: 0; } .navbar-fixed-bottom { bottom: 0; } .navbar .nav { position: relative; left: 0; display: block; float: left; margin: 0 10px 0px 0; } .navbar .nav.pull-right { float: right; } .navbar .nav > li { display: block; margin-top: 10px; font-size: 130%; float: left; } .navbar .nav > li > a { float: none; padding: 10px 10px 11px; line-height: 25px; color: #221e50; text-decoration: none; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .navbar .nav > li > a:hover { background-color: transparent; color: #221e50; text-decoration: underline; } .navbar .nav .active > a, .navbar .nav .active > a:hover { color: #221e50; text-decoration: underline; background-color: white; } .navbar .divider-vertical { height: 40px; width: 1px; margin: 0 9px; overflow: hidden; background-color: white; border-right: 1px solid #333333; } .navbar .nav.pull-right { margin-left: 10px; margin-right: 0; } .navbar .dropdown-menu { margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .navbar .dropdown-menu:before { content: ''; display: inline-block; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 9px; } .navbar .dropdown-menu:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 10px; } .navbar-fixed-bottom .dropdown-menu:before { border-top: 7px solid #ccc; border-top-color: rgba(0, 0, 0, 0.2); border-bottom: 0; bottom: -7px; top: auto; } .navbar-fixed-bottom .dropdown-menu:after { border-top: 6px solid #ffffff; border-bottom: 0; bottom: -6px; top: auto; } .navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } .navbar .nav .active .caret { opacity: 1; filter: alpha(opacity=100); } .navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { background-color: transparent; } .navbar .nav .active > .dropdown-toggle:hover { color: #ffffff; } .navbar .nav.pull-right .dropdown-menu, .navbar .nav .dropdown-menu.pull-right { left: auto; right: 0; } .navbar .nav.pull-right .dropdown-menu:before, .navbar .nav .dropdown-menu.pull-right:before { left: auto; right: 12px; } .navbar .nav.pull-right .dropdown-menu:after, .navbar .nav .dropdown-menu.pull-right:after { left: auto; right: 13px; } .breadcrumb { padding: 7px 14px; margin: 0 0 18px; list-style: none; background-color: #fbfbfb; background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); background-image: linear-gradient(top, #ffffff, #f5f5f5); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); border: 1px solid #ddd; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: inset 0 1px 0 #ffffff; -moz-box-shadow: inset 0 1px 0 #ffffff; box-shadow: inset 0 1px 0 #ffffff; } .breadcrumb li { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; text-shadow: 0 1px 0 #ffffff; } .breadcrumb .divider { padding: 0 5px; color: #999999; } .breadcrumb .active a { color: #333333; } .pagination { height: 36px; margin: 18px 0; } .pagination ul { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; margin-left: 0; margin-bottom: 0; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .pagination li { display: inline; } .pagination a { float: left; padding: 0 14px; line-height: 34px; text-decoration: none; border: 1px solid #ddd; border-left-width: 0; } .pagination a:hover, .pagination .active a { background-color: #f5f5f5; } .pagination .active a { color: #999999; cursor: default; } .pagination .disabled span, .pagination .disabled a, .pagination .disabled a:hover { color: #999999; background-color: transparent; cursor: default; } .pagination li:first-child a { border-left-width: 1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .pagination li:last-child a { -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .pagination-centered { text-align: center; } .pagination-right { text-align: right; } .pager { margin-left: 0; margin-bottom: 18px; list-style: none; text-align: center; *zoom: 1; } .pager:before, .pager:after { display: table; content: ""; } .pager:after { clear: both; } .pager li { display: inline; } .pager a { display: inline-block; padding: 5px 14px; background-color: #fff; border: 1px solid #ddd; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; } .pager a:hover { text-decoration: none; background-color: #f5f5f5; } .pager .next a { float: right; } .pager .previous a { float: left; } .pager .disabled a, .pager .disabled a:hover { color: #999999; background-color: #fff; cursor: default; } .modal-open .dropdown-menu { z-index: 2050; } .modal-open .dropdown.open { *z-index: 2050; } .modal-open .popover { z-index: 2060; } .modal-open .tooltip { z-index: 2070; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000000; } .modal-backdrop.fade { opacity: 0; } .modal-backdrop, .modal-backdrop.fade.in { opacity: 0.8; filter: alpha(opacity=80); } .modal { position: fixed; top: 50%; left: 50%; z-index: 1050; overflow: auto; width: 560px; margin: -250px 0 0 -280px; background-color: #ffffff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.3); *border: 1px solid #999; /* IE6-7 */ -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -webkit-background-clip: padding-box; -moz-background-clip: padding-box; background-clip: padding-box; } .modal.fade { -webkit-transition: opacity .3s linear, top .3s ease-out; -moz-transition: opacity .3s linear, top .3s ease-out; -ms-transition: opacity .3s linear, top .3s ease-out; -o-transition: opacity .3s linear, top .3s ease-out; transition: opacity .3s linear, top .3s ease-out; top: -25%; } .modal.fade.in { top: 50%; } .modal-header { padding: 9px 15px; border-bottom: 1px solid #eee; } .modal-header .close { margin-top: 2px; } .modal-body { overflow-y: auto; max-height: 400px; padding: 15px; } .modal-form { margin-bottom: 0; } .modal-footer { padding: 14px 15px 15px; margin-bottom: 0; text-align: right; background-color: #f5f5f5; border-top: 1px solid #ddd; -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; -webkit-box-shadow: inset 0 1px 0 #ffffff; -moz-box-shadow: inset 0 1px 0 #ffffff; box-shadow: inset 0 1px 0 #ffffff; *zoom: 1; } .modal-footer:before, .modal-footer:after { display: table; content: ""; } .modal-footer:after { clear: both; } .modal-footer .btn + .btn { margin-left: 5px; margin-bottom: 0; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .tooltip { position: absolute; z-index: 1020; display: block; visibility: visible; padding: 5px; font-size: 11px; opacity: 0; filter: alpha(opacity=0); } .tooltip.in { opacity: 0.8; filter: alpha(opacity=80); } .tooltip.top { margin-top: -2px; } .tooltip.right { margin-left: 2px; } .tooltip.bottom { margin-top: 2px; } .tooltip.left { margin-left: -2px; } .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid #000000; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #000000; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 5px solid #000000; } .tooltip-inner { max-width: 200px; padding: 3px 8px; color: #ffffff; text-align: center; text-decoration: none; background-color: #000000; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .tooltip-arrow { position: absolute; width: 0; height: 0; } .popover { position: absolute; top: 0; left: 0; z-index: 1010; display: none; padding: 5px; } .popover.top { margin-top: -5px; } .popover.right { margin-left: 5px; } .popover.bottom { margin-top: 5px; } .popover.left { margin-left: -5px; } .popover.top .arrow { bottom: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #000000; } .popover.right .arrow { top: 50%; left: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 5px solid #000000; } .popover.bottom .arrow { top: 0; left: 50%; margin-left: -5px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #000000; } .popover.left .arrow { top: 50%; right: 0; margin-top: -5px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-left: 5px solid #000000; } .popover .arrow { position: absolute; width: 0; height: 0; } .popover-inner { padding: 3px; width: 280px; overflow: hidden; background: #000000; background: rgba(0, 0, 0, 0.8); -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); } .popover-title { padding: 9px 15px; line-height: 1; background-color: #f5f5f5; border-bottom: 1px solid #eee; -webkit-border-radius: 3px 3px 0 0; -moz-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .popover-content { padding: 14px; background-color: #ffffff; -webkit-border-radius: 0 0 3px 3px; -moz-border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px; -webkit-background-clip: padding-box; -moz-background-clip: padding-box; background-clip: padding-box; } .popover-content p, .popover-content ul, .popover-content ol { margin-bottom: 0; } .thumbnails { margin-left: -20px; list-style: none; *zoom: 1; } .thumbnails:before, .thumbnails:after { display: table; content: ""; } .thumbnails:after { clear: both; } .thumbnails > li { float: left; margin: 0 0 18px 20px; } .thumbnail { display: block; padding: 4px; line-height: 1; border: 1px solid #ddd; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); } a.thumbnail:hover { border-color: #0088cc; -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); } .thumbnail > img { display: block; max-width: 100%; margin-left: auto; margin-right: auto; } .thumbnail .caption { padding: 9px; } .label { padding: 1px 4px 2px; font-size: 10.998px; font-weight: bold; line-height: 13px; color: #ffffff; vertical-align: middle; white-space: nowrap; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #999999; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .label:hover { color: #ffffff; text-decoration: none; } .label-important { background-color: #b94a48; } .label-important:hover { background-color: #953b39; } .label-warning { background-color: #f89406; } .label-warning:hover { background-color: #c67605; } .label-success { background-color: #468847; } .label-success:hover { background-color: #356635; } .label-info { background-color: #3a87ad; } .label-info:hover { background-color: #2d6987; } .label-inverse { background-color: #333333; } .label-inverse:hover { background-color: #1a1a1a; } .badge { padding: 1px 9px 2px; font-size: 12.025px; font-weight: bold; white-space: nowrap; color: #ffffff; background-color: #999999; -webkit-border-radius: 9px; -moz-border-radius: 9px; border-radius: 9px; } .badge:hover { color: #ffffff; text-decoration: none; cursor: pointer; } .badge-error { background-color: #b94a48; } .badge-error:hover { background-color: #953b39; } .badge-warning { background-color: #f89406; } .badge-warning:hover { background-color: #c67605; } .badge-success { background-color: #468847; } .badge-success:hover { background-color: #356635; } .badge-info { background-color: #3a87ad; } .badge-info:hover { background-color: #2d6987; } .badge-inverse { background-color: #333333; } .badge-inverse:hover { background-color: #1a1a1a; } @-webkit-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @-moz-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @-ms-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } .progress { overflow: hidden; height: 18px; margin-bottom: 18px; background-color: #f7f7f7; background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: linear-gradient(top, #f5f5f5, #f9f9f9); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .progress .bar { width: 0%; height: 18px; color: #ffffff; font-size: 12px; text-align: center; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e90d2; background-image: -moz-linear-gradient(top, #149bdf, #0480be); background-image: -ms-linear-gradient(top, #149bdf, #0480be); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); background-image: -webkit-linear-gradient(top, #149bdf, #0480be); background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(top, #149bdf, #0480be); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; -webkit-transition: width 0.6s ease; -moz-transition: width 0.6s ease; -ms-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; } .progress-striped .bar { background-color: #149bdf; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -webkit-background-size: 40px 40px; -moz-background-size: 40px 40px; -o-background-size: 40px 40px; background-size: 40px 40px; } .progress.active .bar { -webkit-animation: progress-bar-stripes 2s linear infinite; -moz-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-danger .bar { background-color: #dd514c; background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); background-image: linear-gradient(top, #ee5f5b, #c43c35); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); } .progress-danger.progress-striped .bar { background-color: #ee5f5b; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-success .bar { background-color: #5eb95e; background-image: -moz-linear-gradient(top, #62c462, #57a957); background-image: -ms-linear-gradient(top, #62c462, #57a957); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); background-image: -webkit-linear-gradient(top, #62c462, #57a957); background-image: -o-linear-gradient(top, #62c462, #57a957); background-image: linear-gradient(top, #62c462, #57a957); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); } .progress-success.progress-striped .bar { background-color: #62c462; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-info .bar { background-color: #4bb1cf; background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); background-image: -o-linear-gradient(top, #5bc0de, #339bb9); background-image: linear-gradient(top, #5bc0de, #339bb9); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); } .progress-info.progress-striped .bar { background-color: #5bc0de; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-warning .bar { background-color: #faa732; background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -ms-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); } .progress-warning.progress-striped .bar { background-color: #fbb450; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .accordion { margin-bottom: 18px; } .accordion-group { margin-bottom: 2px; border: 1px solid #e5e5e5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .accordion-heading { border-bottom: 0; } .accordion-heading .accordion-toggle { display: block; padding: 8px 15px; } .accordion-inner { padding: 9px 15px; border-top: 1px solid #e5e5e5; } .carousel { position: relative; margin-bottom: 18px; line-height: 1; } .carousel-inner { overflow: hidden; width: 100%; position: relative; } .carousel .item { display: none; position: relative; -webkit-transition: 0.6s ease-in-out left; -moz-transition: 0.6s ease-in-out left; -ms-transition: 0.6s ease-in-out left; -o-transition: 0.6s ease-in-out left; transition: 0.6s ease-in-out left; } .carousel .item > img { display: block; line-height: 1; } .carousel .active, .carousel .next, .carousel .prev { display: block; } .carousel .active { left: 0; } .carousel .next, .carousel .prev { position: absolute; top: 0; width: 100%; } .carousel .next { left: 100%; } .carousel .prev { left: -100%; } .carousel .next.left, .carousel .prev.right { left: 0; } .carousel .active.left { left: -100%; } .carousel .active.right { left: 100%; } .carousel-control { position: absolute; top: 40%; left: 15px; width: 40px; height: 40px; margin-top: -20px; font-size: 60px; font-weight: 100; line-height: 30px; color: #ffffff; text-align: center; background: #222222; border: 3px solid #ffffff; -webkit-border-radius: 23px; -moz-border-radius: 23px; border-radius: 23px; opacity: 0.5; filter: alpha(opacity=50); } .carousel-control.right { left: auto; right: 15px; } .carousel-control:hover { color: #ffffff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } .carousel-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 15px 5px; background: #333333; background: rgba(0, 0, 0, 0.75); } .carousel-caption h4, .carousel-caption p { color: #ffffff; } .hero-unit { padding: 60px; margin-bottom: 30px; background-color: #eeeeee; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .hero-unit h1 { margin-bottom: 0; font-size: 60px; line-height: 1; color: inherit; letter-spacing: -1px; } .hero-unit p { font-size: 18px; font-weight: 200; line-height: 27px; color: inherit; } .pull-right { float: right; } .pull-left { float: left; } .hide { display: none; } .show { display: block; } .invisible { visibility: hidden; } td.status-head { font-weight:bold; width:150px; padding:7px; }floodlight-0.90/src/main/resources/web/lib/0000775000175000017500000000000012041336206021316 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/js/0000775000175000017500000000000012041336206021164 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/js/utils.js0000664000175000017500000000177312041336206022672 0ustar jamespagejamespage// template loader from Christophe Coenraets tpl = { // Hash of preloaded templates for the app templates:{}, // Recursively pre-load all the templates for the app. // This implementation should be changed in a production environment. All the template files should be // concatenated in a single file. loadTemplates:function (names, callback) { var that = this; var loadTemplate = function (index) { var name = names[index]; console.log('Loading template: ' + name); $.get('tpl/' + name + '.html', function (data) { that.templates[name] = data; index++; if (index < names.length) { loadTemplate(index); } else { callback(); } }); } loadTemplate(0); }, // Get template by name from hash of preloaded templates get:function (name) { return this.templates[name]; } };floodlight-0.90/src/main/resources/web/js/models/0000775000175000017500000000000012041336206022447 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/js/models/statusmodel.js0000664000175000017500000000401212041336206025346 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Status = Backbone.Model.extend({ defaults: { host: 'localhost', ofport: 6633, uptime: 'unknown', free: 0, total: 0, healthy: 'unknown', modules: [], moduleText: '' }, initialize:function () { var self = this; console.log("fetching controller status"); $.ajax({ url:hackBase + "/wm/core/health/json", dataType:"json", success:function (data) { console.log("fetched controller status: health"); self.set(data); // console.log(self.toJSON()); } }); $.ajax({ url:hackBase + "/wm/core/memory/json", dataType:"json", success:function (data) { console.log("fetched controller status: memory"); self.set(data); // console.log(self.toJSON()); } }); $.ajax({ url:hackBase + "/wm/core/module/loaded/json", dataType:"json", success:function (data) { console.log("fetched controller status: modules loaded"); // console.log(data); self.set({modules:_.keys(data)}); self.set({moduleText:_.reduce(_.keys(data), function(s, m) {return s+m.replace("net.floodlightcontroller", "n.f")+", "}, '')}); } }); } });floodlight-0.90/src/main/resources/web/js/models/switchmodel.js0000664000175000017500000002632712041336206025341 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Switch = Backbone.Model.extend({ urlRoot:"/wm/core/switch/", defaults: { datapathDescription: '', hardwareDescription: '', manufacturerDescription: '', serialNumber: '', softwareDescription: '', flowCount: ' ', packetCount: ' ', byteCount: ' ', }, initialize:function () { var self = this; //console.log("fetching switch " + this.id + " desc") $.ajax({ url:hackBase + "/wm/core/switch/" + self.id + '/desc/json', dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " desc"); //console.log(data[self.id][0]); self.set(data[self.id][0]); } }); //console.log("fetching switch " + this.id + " aggregate") $.ajax({ url:hackBase + "/wm/core/switch/" + self.id + '/aggregate/json', dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " aggregate"); //console.log(data[self.id][0]); self.set(data[self.id][0]); } }); self.trigger('add'); this.ports = new PortCollection(); this.flows = new FlowCollection(); //this.loadPorts(); //this.loadFlows(); }, fetch:function () { this.initialize() }, loadPorts:function () { var self = this; //console.log("fetching switch " + this.id + " ports") //console.log("fetching switch " + this.id + " features") $.when($.ajax({ url:hackBase + "/wm/core/switch/" + self.id + '/port/json', dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " ports"); //console.log(data[self.id]); // create port models _.each(data[self.id], function(p) { p.id = self.id+'-'+p.portNumber; p.dropped = p.receiveDropped + p.transmitDropped; p.errors = p.receiveCRCErrors + p.receiveErrors + p.receiveOverrunErrors + p.receiveFrameErrors + p.transmitErrors; // this is a knda kludgy way to merge models var m = self.ports.get(p.id); if(m) { m.set(p, {silent: true}); } else { self.ports.add(p, {silent: true}); } //console.log(p); }); } }), $.ajax({ url:hackBase + "/wm/core/switch/" + self.id + '/features/json', dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " features"); //console.log(data[self.id]); // update port models _.each(data[self.id].ports, function(p) { p.id = self.id+'-'+p.portNumber; if(p.name != p.portNumber) { p.name = p.portNumber + ' (' + p.name + ')'; } p.status = ''; p.status += (p.state & 1) ? 'DOWN' : 'UP'; switch(p.currentFeatures & 0x7f) { case 1: p.status += ' 10 Mbps'; break; case 2: p.status += ' 10 Mbps FDX'; break; case 4: p.status += ' 100 Mbps'; break; case 8: p.status += ' 100 Mbps FDX'; break; case 16: p.status += ' 1 Gbps'; // RLY? break; case 32: p.status += ' 1 Gbps FDX'; break; case 64: p.status += ' 10 Gbps FDX'; break; } // TODO parse copper/fiber, autoneg, pause // this is a knda kludgy way to merge models var m = self.ports.get(p.id); if(m) { m.set(p, {silent: true}); } else { self.ports.add(p, {silent: true}); } //console.log(p); }); } })).done(function() { self.ports.trigger('add'); // batch redraws }); }, loadFlows:function () { var self = this; //console.log("fetching switch " + this.id + " flows") $.ajax({ url:hackBase + "/wm/core/switch/" + self.id + '/flow/json', dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " flows"); var flows = data[self.id]; //console.log(flows); // create flow models var i = 0; _.each(flows, function(f) { f.id = self.id + '-' + i++; // build human-readable match f.matchHTML = ''; if(!(f.match.wildcards & (1<<0))) { // input port f.matchHTML += "port=" + f.match.inputPort + ", "; } if(!(f.match.wildcards & (1<<1))) { // VLAN ID f.matchHTML += "VLAN=" + f.match.dataLayerVirtualLan + ", "; } if(!(f.match.wildcards & (1<<20))) { // VLAN prio f.matchHTML += "prio=" + f.match.dataLayerVirtualLanPriorityCodePoint + ", "; } if(!(f.match.wildcards & (1<<2))) { // src MAC f.matchHTML += "src=" + f.match.dataLayerSource + ", "; } if(!(f.match.wildcards & (1<<3))) { // dest MAC f.matchHTML =+ "dest=" + f.match.dataLayerDestination + ", "; } if(!(f.match.wildcards & (1<<4))) { // Ethertype // TODO print a human-readable name instead of hex f.matchHTML += "ethertype=" + f.match.dataLayerType + ", "; } if(!(f.match.wildcards & (1<<5))) { // IP protocol // TODO print a human-readable name f.matchHTML += "proto=" + f.match.networkProtocol + ", "; } if(!(f.match.wildcards & (1<<6))) { // TCP/UDP source port f.matchHTML += "IP src port=" + f.match.transportSource + ", "; } if(!(f.match.wildcards & (1<<7))) { // TCP/UDP dest port f.matchHTML += "IP dest port=" + f.match.transportDestination + ", "; } if(!(f.match.wildcards & (32<<8))) { // src IP f.matchHTML += "src=" + f.match.networkSource + ", "; } if(!(f.match.wildcards & (32<<14))) { // dest IP f.matchHTML += "dest=" + f.match.networkDestination + ", "; } if(!(f.match.wildcards & (1<<21))) { // IP TOS f.matchHTML += "TOS=" + f.match.networkTypeOfService + ", "; } // remove trailing ", " f.matchHTML = f.matchHTML.substr(0, f.matchHTML.length - 2); // build human-readable action list f.actionText = _.reduce(f.actions, function (memo, a) { switch (a.type) { case "OUTPUT": return memo + "output " + a.port + ', '; case "OPAQUE_ENQUEUE": return memo + "enqueue " + a.port + ':' + a.queueId + ', '; case "STRIP_VLAN": return memo + "strip VLAN, "; case "SET_VLAN_ID": return memo + "VLAN=" + a.virtualLanIdentifier + ', '; case "SET_VLAN_PCP": return memo + "prio=" + a.virtualLanPriorityCodePoint + ', '; case "SET_DL_SRC": return memo + "src=" + a.dataLayerAddress + ', '; case "SET_DL_DST": return memo + "dest=" + a.dataLayerAddress + ', '; case "SET_NW_TOS": return memo + "TOS=" + a.networkTypeOfService + ', '; case "SET_NW_SRC": return memo + "src=" + a.networkAddress + ', '; case "SET_NW_DST": return memo + "dest=" + a.networkAddress + ', '; case "SET_TP_SRC": return memo + "src port=" + a.transportPort + ', '; case "SET_TP_DST": return memo + "dest port=" + a.transportPort + ', '; } }, ""); // remove trailing ", " f.actionText = f.actionText.substr(0, f.actionText.length - 2); //console.log(f); self.flows.add(f, {silent: true}); }); self.flows.trigger('add'); } }); }, }); window.SwitchCollection = Backbone.Collection.extend({ model:Switch, initialize:function () { var self = this; //console.log("fetching switch list") $.ajax({ url:hackBase + "/wm/core/controller/switches/json", dataType:"json", success:function (data) { //console.log("fetched switch list: " + data.length); //console.log(data); _.each(data, function(sw) {self.add({id: sw['dpid'], inetAddress: sw.inetAddress, connectedSince: new Date(sw.connectedSince).toLocaleString()})}); } }); }, fetch:function () { this.initialize() } }); floodlight-0.90/src/main/resources/web/js/models/portmodel.js0000664000175000017500000000207312041336206025014 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Port = Backbone.Model.extend({ defaults: { name: '', receiveBytes: 0, receivePackets: 0, transmitBytes: 0, transmitPackets: 0, dropped: 0, errors: 0, }, initialize:function () { // TODO hook up associated hosts } }); window.PortCollection = Backbone.Collection.extend({ model:Port, // instead of the collection loading its children, the switch will load them initialize:function () {} });floodlight-0.90/src/main/resources/web/js/models/topologymodel.js0000664000175000017500000000425512041336206025710 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Topology = Backbone.Model.extend({ url:"/wm/topology/links/json", defaults:{ nodes: [], links: [], }, initialize:function () { var self = this; console.log("fetching topology") $.ajax({ url:hackBase + self.url, dataType:"json", success:function (data) { console.log("fetched topology: " + data.length); // console.log(data); self.nodes = {}; self.links = []; // step 1: build unique array of switch IDs /* this doesn't work if there's only one switch, because there are no switch-switch links _.each(data, function (l) { self.nodes[l['src-switch']] = true; self.nodes[l['dst-switch']] = true; }); // console.log(self.nodes); var nl = _.keys(self.nodes); */ var nl = swl.pluck('id'); self.nodes = _.map(nl, function (n) {return {name:n}}); // step 2: build array of links in format D3 expects _.each(data, function (l) { self.links.push({source:nl.indexOf(l['src-switch']), target:nl.indexOf(l['dst-switch']), value:10}); }); // console.log(self.nodes); // console.log(self.links); self.trigger('change'); //self.set(data); } }); } });floodlight-0.90/src/main/resources/web/js/models/hostmodel.js0000664000175000017500000000435712041336206025014 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Host = Backbone.Model.extend({ defaults: { // vlan: -1, lastSeen: 'never', ip: ' ', swport: ' ', }, // initialize:function () {} }); window.HostCollection = Backbone.Collection.extend({ model:Host, initialize:function () { var self = this; //console.log("fetching host list") $.ajax({ url:hackBase + "/wm/device/", dataType:"json", success:function (data) { // console.log("fetched host list: " + data.length); // console.log(data); // data is a list of device hashes _.each(data, function(h) { if (h['attachmentPoint'].length > 0) { h.id = h.mac[0]; h.swport = _.reduce(h['attachmentPoint'], function(memo, ap) { return memo + ap.switchDPID + "-" + ap.port + " "}, ""); //console.log(h.swport); h.lastSeen = new Date(h.lastSeen).toLocaleString(); self.add(h, {silent: true}); } }); self.trigger('add'); // batch redraws } }); }, fetch:function () { this.initialize(); } /* * findByName:function (key) { // TODO: Modify service to include firstName * in search var url = (key == '') ? '/host/' : "/host/search/" + key; * console.log('findByName: ' + key); var self = this; $.ajax({ url:url, * dataType:"json", success:function (data) { console.log("search success: " + * data.length); self.reset(data); } }); } */ }); floodlight-0.90/src/main/resources/web/js/models/flowmodel.js0000664000175000017500000000173212041336206025000 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.Flow = Backbone.Model.extend({ defaults: { receiveBytes: 0, receivePackets: 0, transmitBytes: 0, transmitPackets: 0, }, // initialize:function () {} }); window.FlowCollection = Backbone.Collection.extend({ model:Flow, // instead of the collection loading its children, the switch will load them // initialize:function () {} });floodlight-0.90/src/main/resources/web/js/main.js0000664000175000017500000001047412041336206022454 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ var hackBase = ""; // put a URL here to access a different REST server var AppRouter = Backbone.Router.extend({ routes:{ "":"home", "topology":"topology", "switches":"switchList", "switch/:id":"switchDetails", "switch/:id/port/:p":"portDetails", // not clear if needed "hosts":"hostList", "host/:id":"hostDetails", // "vlans":"vlanList" // maybe one day // "vlan/:id":"vlanDetails" }, initialize:function () { this.headerView = new HeaderView(); $('.header').html(this.headerView.render().el); // Close the search dropdown on click anywhere in the UI $('body').click(function () { $('.dropdown').removeClass("open"); }); }, home:function () { $('#content').html(new HomeView().render().el); $('ul[class="nav"] > li').removeClass('active'); $('a[href="/"]').parent().addClass('active'); }, topology:function () { //console.log("switching to topology view"); var topo = new Topology(); $('#content').html(new TopologyView({model:topo, hosts:hl}).render().el); // TODO factor this code out $('ul.nav > li').removeClass('active'); $('li > a[href*="topology"]').parent().addClass('active'); }, switchDetails:function (id) { //console.log("switching [sic] to single switch view"); var sw = swl.get(id); $('#content').html(new SwitchView({model:sw}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/switches"]').parent().addClass('active'); }, switchList:function () { //console.log("switching [sic] to switch list view"); $('#content').html(new SwitchListView({model:swl}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/switches"]').parent().addClass('active'); }, hostDetails:function (id) { //console.log("switching to single host view"); var h = hl.get(id); $('#content').html(new HostView({model:h}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/hosts"]').parent().addClass('active'); }, hostList:function () { //console.log("switching to host list view"); $('#content').html(new HostListView({model:hl}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/hosts"]').parent().addClass('active'); }, }); // load global models and reuse them var swl = new SwitchCollection(); var hl = new HostCollection(); tpl.loadTemplates(['home', 'status', 'topology', 'header', 'switch', 'switch-list', 'switch-list-item', 'host', 'host-list', 'host-list-item', 'port-list', 'port-list-item', 'flow-list', 'flow-list-item'], function () { app = new AppRouter(); Backbone.history.start({pushState: true}); // console.log("started history") $(document).ready(function () { // trigger Backbone routing when clicking on links, thanks to Atinux and pbnv app.navigate("", true); window.document.addEventListener('click', function(e) { e = e || window.event var target = e.target || e.srcElement if ( target.nodeName.toLowerCase() === 'a' ) { e.preventDefault() var uri = target.getAttribute('href') app.navigate(uri.substr(1), true) } }); window.addEventListener('popstate', function(e) { app.navigate(location.pathname.substr(1), true); }); }); }); setInterval(function () { swl.fetch(); }, 3000); setInterval(function () { hl.fetch(); }, 3000); floodlight-0.90/src/main/resources/web/js/views/0000775000175000017500000000000012041336206022321 5ustar jamespagejamespagefloodlight-0.90/src/main/resources/web/js/views/status.js0000664000175000017500000000173012041336206024203 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.StatusView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('status')); this.model.bind("change", this.render, this); }, render:function (eventName) { // console.log("rendering status"); $(this.el).html(this.template(this.model.toJSON())); //$(this.el).html(this.template()); return this; } });floodlight-0.90/src/main/resources/web/js/views/flow.js0000664000175000017500000000401412041336206023625 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // not used for now window.FlowView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('flow')); this.model.bind("change", this.render, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); window.FlowListItemView = Backbone.View.extend({ tagName:"tr", initialize:function () { this.template = _.template(tpl.get('flow-list-item')); this.model.bind("change", this.render, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); // TODO throughput (bps) and pps sparklines would be nice here // TODO hovering over a MAC address could show a compact view of that host window.FlowListView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('flow-list')); this.model.bind("change", this.render, this); this.model.bind("add", this.render, this); }, render:function (eventName) { // console.log("rendering flow list view: " + this.model.models.length); $(this.el).html(this.template({nflows:this.model.length})); _.each(this.model.models, function (f) { $(this.el).find('table.flow-table > tbody') .append(new FlowListItemView({model:f}).render().el); }, this); return this; }, }); floodlight-0.90/src/main/resources/web/js/views/header.js0000664000175000017500000000270412041336206024112 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.HeaderView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('header')); // this.searchResults = new HostCollection(); // this.searchresultsView = new SearchListView({model:this.searchResults, className:'dropdown-menu'}); }, render:function (eventName) { $(this.el).html(this.template()); // $('.navbar-search', this.el).append(this.searchresultsView.render().el); return this; }, events:{ "keyup .search-query":"search" }, search:function (event) { // var key = event.target.value; var key = $('#searchText').val(); console.log('search ' + key); // TODO search the host and switch lists this.searchResults.findByName(key); setTimeout(function () { $('#searchForm').addClass('open'); }); } });floodlight-0.90/src/main/resources/web/js/views/topology.js0000664000175000017500000001120312041336206024530 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.TopologyView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('topology')); this.model.bind("change", this.render, this); this.hosts = this.options.hosts.models; this.host_links = []; }, render:function (eventName) { $(this.el).html(this.template()); var width = 900, height = 600; var color = d3.scale.category20(); var force = d3.layout.force() .charge(-500) .linkDistance(200) .size([width, height]); var svg = d3.select("#topology-graph").append("svg") .attr("width", width) .attr("height", height); if(this.model.nodes) { for (var i = 0; i < this.model.nodes.length; i++) { this.model.nodes[i].group = 1; this.model.nodes[i].id = this.model.nodes[i].name; } for (var i = 0; i < this.hosts.length; i++) { host = this.hosts[i]; if (host.attributes['ipv4'].length > 0) { host.name = host.attributes['ipv4'][0] + "\n" + host.id; } else { host.name = host.id; } host.group = 2; //console.log(host); } var all_nodes = this.model.nodes.concat(this.hosts); var all_nodes_map = []; _.each(all_nodes, function(n) { all_nodes_map[n.id] = n; }); for (var i = 0; i < this.hosts.length; i++) { host = this.hosts[i]; //for (var j = 0; j < host.attributes['attachmentPoint'].length; j++) { for (var j = 0; j < 1; j++) { // FIXME hack to ignore multiple APs var link = {source:all_nodes_map[host.id], target:all_nodes_map[host.attributes['attachmentPoint'][j]['switchDPID']], value:10}; //console.log(link); if ( link.source && link.target) { this.host_links.push(link); } else { console.log("Error: skipping link with undefined stuff!") } } } var all_links = this.model.links.concat(this.host_links); force.nodes(all_nodes).links(all_links).start(); var link = svg.selectAll("line.link").data(all_links).enter() .append("line").attr("class", "link") .style("stroke", function (d) { return "black"; }); var node = svg.selectAll(".node").data(all_nodes) .enter().append("g") .attr("class", "node") .call(force.drag); node.append("image") .attr("xlink:href", function (d) {return d.group==1 ? "/ui/img/switch.png" : "/ui/img/server.png"}) .attr("x", -16).attr("y", -16) .attr("width", 32).attr("height", 32); node.append("text").attr("dx", 20).attr("dy", ".35em") .text(function(d) { return d.name }); node.on("click", function (d) { // TODO we could add some functionality here console.log('clicked '+d.name); }); node.append("title").text(function(d) { return d.name; }); force.on("tick", function() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); }); } return this; } }); floodlight-0.90/src/main/resources/web/js/views/switch.js0000664000175000017500000000430512041336206024162 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.SwitchView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('switch')); this.model.bind("change", this.render, this); //this.model.bind("destroy", this.close, this); // some parts of the model are large and are only needed in detail view this.model.loadPorts(); this.model.loadFlows(); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); $(this.el).find('#port-list').html(new PortListView({model:this.model.ports}).render().el); $(this.el).find('#flow-list').html(new FlowListView({model:this.model.flows}).render().el); return this; } }); window.SwitchListItemView = Backbone.View.extend({ tagName:"tr", initialize:function () { this.template = _.template(tpl.get('switch-list-item')); this.model.bind("change", this.render, this); //this.model.bind("destroy", this.close, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); window.SwitchListView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('switch-list')); this.model.bind("change", this.render, this); }, render:function (eventName) { $(this.el).html(this.template({nswitches:swl.length})); _.each(this.model.models, function (sw) { $(this.el).find('table.switch-table > tbody') .append(new SwitchListItemView({model:sw}).render().el); }, this); return this; }, }); floodlight-0.90/src/main/resources/web/js/views/port.js0000664000175000017500000000400612041336206023643 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // not used for now window.PortView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('port')); this.model.bind("change", this.render, this); //this.model.bind("destroy", this.close, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); window.PortListItemView = Backbone.View.extend({ tagName:"tr", initialize:function () { this.template = _.template(tpl.get('port-list-item')); this.model.bind("change", this.render, this); //this.model.bind("destroy", this.close, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); // TODO throughput sparklines would be nice here window.PortListView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('port-list')); this.model.bind("change", this.render, this); this.model.bind("add", this.render, this); }, render:function (eventName) { // console.log("rendering port list view"); $(this.el).html(this.template({nports:this.model.length})); _.each(this.model.models, function (p) { $(this.el).find('table.port-table > tbody') .append(new PortListItemView({model:p}).render().el); }, this); return this; }, }); floodlight-0.90/src/main/resources/web/js/views/home.js0000664000175000017500000000244312041336206023612 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.HomeView = Backbone.View.extend({ initialize:function () { // console.log('Initializing Home View'); this.template = _.template(tpl.get('home')); }, events:{ "click #showMeBtn":"showMeBtnClick" }, render:function (eventName) { $(this.el).html(this.template()); var stats = new Status(); $(this.el).find('#controller-status').html(new StatusView({model:stats}).render().el); $(this.el).find('#switch-list').html(new SwitchListView({model:swl}).render().el); $(this.el).find('#host-list').html(new HostListView({model:hl}).render().el); return this; }, showMeBtnClick:function () { app.headerView.search(); } });floodlight-0.90/src/main/resources/web/js/views/host.js0000664000175000017500000000362312041336206023640 0ustar jamespagejamespage/* Copyright 2012 IBM Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ window.HostView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('host')); this.model.bind("change", this.render, this); this.model.bind("add", this.render, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } }); window.HostListView = Backbone.View.extend({ initialize:function () { var self = this; this.template = _.template(tpl.get('host-list')); this.model.bind("change", this.render, this); this.model.bind("add", this.render, this); }, render:function (eventName) { $(this.el).html(this.template({nhosts:hl.length})); _.each(this.model.models, function (h) { $(this.el).find('table.host-table > tbody') .append(new HostListItemView({model:h}).render().el); }, this); return this; } }); window.HostListItemView = Backbone.View.extend({ tagName:"tr", initialize:function () { this.template = _.template(tpl.get('host-list-item')); this.model.bind("change", this.render, this); this.model.bind("destroy", this.close, this); }, render:function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; } });floodlight-0.90/src/main/resources/web/index.html0000664000175000017500000000637212041336206022555 0ustar jamespagejamespage Floodlight
floodlight-0.90/src/main/resources/quantum.properties0000664000175000017500000000155112041336206023605 0ustar jamespagejamespage# The default configuration for openstack floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\ net.floodlightcontroller.core.FloodlightProvider,\ net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\ net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ net.floodlightcontroller.forwarding.Forwarding,\ net.floodlightcontroller.jython.JythonDebugInterface,\ net.floodlightcontroller.counter.CounterStore,\ net.floodlightcontroller.perfmon.PktInProcessingTime,\ net.floodlightcontroller.ui.web.StaticWebRoutable,\ net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter,\ net.floodlightcontroller.threadpool.ThreadPool net.floodlightcontroller.restserver.RestApiServer.port = 8080 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633 net.floodlightcontroller.jython.JythonDebugInterface.port = 6655floodlight-0.90/src/main/python/0000775000175000017500000000000012041336206017302 5ustar jamespagejamespagefloodlight-0.90/src/main/python/PythonClient.py0000664000175000017500000000221712041336206022276 0ustar jamespagejamespage#!/usr/bin/env python import sys sys.path.append('../../../target/gen-py') from packetstreamer import PacketStreamer from packetstreamer.ttypes import * from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol try: # Make socket transport = TSocket.TSocket('localhost', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TFramedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = PacketStreamer.Client(protocol) # Connect! transport.open() while 1: packets = client.getPackets("session1") print 'session1 packets num: %d' % (len(packets)) count = 1 for packet in packets: print "Packet %d: %s"% (count, packet) if "FilterTimeout" in packet: sys.exit() count += 1 # Close! transport.close() except Thrift.TException, tx: print '%s' % (tx.message) except KeyboardInterrupt, e: print 'Bye-bye' floodlight-0.90/src/main/python/PythonServer.py0000664000175000017500000000277112041336206022333 0ustar jamespagejamespage#!/usr/bin/env python import sys import logging sys.path.append('../../../target/gen-py') from packetstreamer import PacketStreamer from packetstreamer.ttypes import * from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer class PacketStreamerHandler: def __init__(self): logging.handlers.codecs = None self.log = logging.getLogger("packetstreamer") self.log.setLevel(logging.DEBUG) handler = logging.handlers.SysLogHandler("/dev/log") handler.setFormatter(logging.Formatter("%(name)s: %(levelname)s %(message)s")) self.log.addHandler(handler) def ping(self): self.log.debug('ping()') return true def pushPacketSync(self, packet): self.log.debug('receive a packet synchronously: %s' %(packet)) return 0 def pushPacketAsync(self, packet): self.log.debug('receive a packet Asynchronously: %s' %(packet)) handler = PacketStreamerHandler() processor = PacketStreamer.Processor(handler) transport = TSocket.TServerSocket(9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) # You could do one of these for a multithreaded server #server = TServer.TThreadedServer(processor, transport, tfactory, pfactory) #server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) print 'Starting the server...' server.serve() print 'done.' floodlight-0.90/src/main/python/debugserver.py0000664000175000017500000000411312041336206022170 0ustar jamespagejamespage#!/usr/bin/env python import sys from threading import currentThread from SocketServer import BaseRequestHandler, TCPServer from code import InteractiveConsole _locals = None class DebugLogger(object): def do_print(self, *args): for i in args: print i, print info = do_print warn = do_print debug = do_print _log = DebugLogger() class DebugConsole(InteractiveConsole): def __init__(self, request): self.request = request InteractiveConsole.__init__(self, _locals) def raw_input(self, prompt): self.request.send(prompt) data = self.request.recv(10000).rstrip() if len(data) == 1 and ord(data[0]) == 4: sys.exit() return data def write(self, data): self.request.send(str(data)) def write_nl(self, data): self.write(str(data)+"\r\n") class DebugServerHandler(BaseRequestHandler): def __init__(self, request, client_address, server): currentThread()._thread.setName("debugserver-%s:%d" % client_address) _log.debug('Open connection to DebugServer from %s:%d' % client_address) BaseRequestHandler.__init__(self, request, client_address, server) def handle(self): console = DebugConsole(self.request) sys.displayhook = console.write_nl console.interact('DebugServer') self.request.close() class DebugServer(TCPServer): daemon_threads = True allow_reuse_address = True def handle_error(self, request, client_address): _log.debug('Closing connection to DebugServer from %s:%d' % client_address) request.close() def run_server(port=6655, host='0.0.0.0', locals=locals()): currentThread()._thread.setName("debugserver-main") global _locals _locals = locals if "log" in locals.keys(): global _log _log = locals["log"] _log.info("Starting DebugServer on port %d" % port) server = DebugServer(('', port), DebugServerHandler) try: server.serve_forever() except KeyboardInterrupt: pass if __name__ == "__main__": run_server() floodlight-0.90/src/main/python/compileall.py0000664000175000017500000001224312041336206021777 0ustar jamespagejamespage"""Module/script to "compile" all .py files to .pyc (or .pyo) file. When called as a script with arguments, this compiles the directories given as arguments recursively; the -l option prevents it from recursing into directories. Without arguments, if compiles all modules on sys.path, without recursing into subdirectories. (Even though it should do so for packages -- for now, you'll have to deal with packages separately.) See module py_compile for details of the actual byte-compilation. """ import os import sys import py_compile __all__ = ["compile_dir","compile_path"] def compile_dir(dir, maxlevels=10, ddir=None, force=0, rx=None, quiet=0): """Byte-compile all modules in the given directory tree. Arguments (only dir is required): dir: the directory to byte-compile maxlevels: maximum recursion level (default 10) ddir: if given, purported directory name (this is the directory name that will show up in error messages) force: if 1, force compilation, even if timestamps are up-to-date quiet: if 1, be quiet during compilation """ if not quiet: print 'Listing', dir, '...' try: names = os.listdir(dir) except os.error: print "Can't list", dir names = [] names.sort() success = 1 for name in names: fullname = os.path.join(dir, name) if ddir is not None: dfile = os.path.join(ddir, name) else: dfile = None if rx is not None: mo = rx.search(fullname) if mo: continue if os.path.isfile(fullname): head, tail = name[:-3], name[-3:] if tail == '.py': cfile = fullname + (__debug__ and 'c' or 'o') ftime = os.stat(fullname).st_mtime try: ctime = os.stat(cfile).st_mtime except os.error: ctime = 0 if (ctime > ftime) and not force: continue if not quiet: print 'Compiling', fullname, '...' try: ok = py_compile.compile(fullname, None, dfile, True) except KeyboardInterrupt: raise KeyboardInterrupt except py_compile.PyCompileError,err: if quiet: print 'Compiling', fullname, '...' print err.msg success = 0 except IOError, e: print "Sorry", e success = 0 else: if ok == 0: success = 0 elif maxlevels > 0 and \ name != os.curdir and name != os.pardir and \ os.path.isdir(fullname) and \ not os.path.islink(fullname): if not compile_dir(fullname, maxlevels - 1, dfile, force, rx, quiet): success = 0 return success def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0): """Byte-compile all module on sys.path. Arguments (all optional): skip_curdir: if true, skip current directory (default true) maxlevels: max recursion level (default 0) force: as for compile_dir() (default 0) quiet: as for compile_dir() (default 0) """ success = 1 for dir in sys.path: if (not dir or dir == os.curdir) and skip_curdir: print 'Skipping current directory' else: success = success and compile_dir(dir, maxlevels, None, force, quiet=quiet) return success def main(): """Script main program.""" import getopt try: opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:') except getopt.error, msg: print msg print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \ "[-x regexp] [directory ...]" print "-l: don't recurse down" print "-f: force rebuild even if timestamps are up-to-date" print "-q: quiet operation" print "-d destdir: purported directory name for error messages" print " if no directory arguments, -l sys.path is assumed" print "-x regexp: skip files matching the regular expression regexp" print " the regexp is search for in the full path of the file" sys.exit(2) maxlevels = 10 ddir = None force = 0 quiet = 0 rx = None for o, a in opts: if o == '-l': maxlevels = 0 if o == '-d': ddir = a if o == '-f': force = 1 if o == '-q': quiet = 1 if o == '-x': import re rx = re.compile(a) if ddir: if len(args) != 1: print "-d destdir require exactly one directory argument" sys.exit(2) success = 1 try: if args: for dir in args: if not compile_dir(dir, maxlevels, ddir, force, rx, quiet): success = 0 else: success = compile_path() except KeyboardInterrupt: print "\n[interrupt]" success = 0 return success if __name__ == '__main__': exit_status = int(not main()) sys.exit(exit_status) floodlight-0.90/src/main/thrift/0000775000175000017500000000000012041336206017261 5ustar jamespagejamespagefloodlight-0.90/src/main/thrift/packetstreamer.thrift0000664000175000017500000000311212041336206023512 0ustar jamespagejamespage# # Interface definition for packetstreamer service # namespace java net.floodlightcontroller.packetstreamer.thrift namespace cpp net.floodlightcontroller.packetstreamer namespace py packetstreamer namespace php packetstreamer namespace perl packetstreamer const string VERSION = "0.1.0" # # data structures # /** * OFMessage type **/ enum OFMessageType { HELLO = 0, ERROR = 1, ECHO_REQUEST = 2, ECHO_REPLY = 3, VENDOR = 4, FEATURES_REQUEST = 5, FEATURES_REPLY = 6, GET_CONFIG_REQUEST = 7, GET_CONFIG_REPLY = 8, SET_CONFIG = 9, PACKET_IN = 10, FLOW_REMOVED = 11, PORT_STATUS = 12, PACKET_OUT = 13, FLOW_MOD = 14, PORT_MOD = 15, STATS_REQUEST = 16, STATS_REPLY = 17, BARRIER_REQUEST = 18, BARRIER_REPLY = 19, } /** * A struct that defines switch port tuple */ struct SwitchPortTuple { 1: i64 dpid, 2: i16 port, } struct Packet { 1: OFMessageType messageType, 2: SwitchPortTuple swPortTuple, 3: binary data, } struct Message { 1: list sessionIDs, 2: Packet packet, } /** * Packetstreamer API */ service PacketStreamer { /** * Synchronous method to get packets for a given sessionid */ list getPackets(1:string sessionid), /** * Synchronous method to publish a packet. * It ensure the order that the packets are pushed */ i32 pushMessageSync(1:Message packet), /** * Asynchronous method to publish a packet. * Order is not guaranteed. */ oneway void pushMessageAsync(1:Message packet) /** * Terminate a session */ void terminateSession(1:string sessionid) } floodlight-0.90/src/main/java/0000775000175000017500000000000012041336206016702 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/0000775000175000017500000000000012041336206017470 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/0000775000175000017500000000000012041336206023727 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/0000775000175000017500000000000012041336206026521 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java0000664000175000017500000001122512041336206034300 0ustar jamespagejamespage/** * Copyright 2011,2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import java.util.Collection; import java.util.EnumSet; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.internal.Entity; /** * A component that wishes to participate in entity classification needs to * implement the IEntityClassifier interface, and register with the Device * Manager as an entity classifier. An entity is classified by the classifier * into an {@link IEntityClass} * * @author readams */ public interface IEntityClassifierService extends IFloodlightService { /** * Classify the given entity into an IEntityClass. It is important * that the key fields returned by {@link IEntityClassifierService#getKeyFields()} * be sufficient for classifying entities. That is, if two entities are * identical except for a field that is not a key field, they must be * assigned the same class. Furthermore, entity classification must be * transitive: For all entities x, y, z, if x and y belong to a class c, and * y and z belong class c, then x and z must belong to class c. * * @param entity the entity to classify * @return the IEntityClass resulting from the classification. * @see IEntityClassifierService#getKeyFields() */ IEntityClass classifyEntity(Entity entity); /** * Return the most general list of fields that should be used as key * fields. If devices differ in any fields not listed here, they can * never be considered a different device by any {@link IEntityClass} * returned by {@link IEntityClassifierService#classifyEntity}. The key fields * for an entity classifier must not change unless associated with a * flush of all entity state. The list of key fields must be the union * of all key fields that could be returned by * {@link IEntityClass#getKeyFields()}. * * @return a set containing the fields that should not be * wildcarded. May be null to indicate that all fields are key fields. * @see {@link IEntityClass#getKeyFields()} * @see {@link IEntityClassifierService#classifyEntity} */ EnumSet getKeyFields(); /** * Reclassify the given entity into a class. When reclassifying entities, * it can be helpful to take into account the current classification either * as an optimization or to allow flushing any cached state tied to the key * for that device. The entity will be assigned to a new device with a new * object if the entity class returned is different from the entity class for * curDevice. * *

Note that you must take steps to ensure you always return classes * in some consistent ordering. * @param curDevice the device currently associated with the entity * @param entity the entity to reclassify * @return the IEntityClass resulting from the classification */ IEntityClass reclassifyEntity(IDevice curDevice, Entity entity); /** * Once reclassification is complete for a device, this method will be * called. If any entities within the device changed their classification, * it will split into one or more new devices for each of the entities. If * two devices are merged because of a reclassification, then this will be * called on each of the devices, with the same device in the newDevices * collection. * * @param oldDevice the original device object * @param newDevices all the new devices derived from the entities of the * old device. If null, the old device was unchanged. */ void deviceUpdate(IDevice oldDevice, Collection newDevices); /** * Adds a listener to listen for IEntityClassifierServices notifications * * @param listener The listener that wants the notifications */ public void addListener(IEntityClassListener listener); } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java0000664000175000017500000000724112041336206031476 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.ser.ToStringSerializer; /** * A simple switch DPID/port pair * @author readams * */ public class SwitchPort { @JsonSerialize(using=ToStringSerializer.class) public enum ErrorStatus { DUPLICATE_DEVICE("duplicate-device"); private String value; ErrorStatus(String v) { value = v; } @Override public String toString() { return value; } public static ErrorStatus fromString(String str) { for (ErrorStatus m : ErrorStatus.values()) { if (m.value.equals(str)) { return m; } } return null; } } protected long switchDPID; protected int port; ErrorStatus errorStatus; /** * Simple constructor * @param switchDPID the dpid * @param port the port * @param errorStatus any error status for the switch port */ public SwitchPort(long switchDPID, int port, ErrorStatus errorStatus) { super(); this.switchDPID = switchDPID; this.port = port; this.errorStatus = errorStatus; } /** * Simple constructor * @param switchDPID the dpid * @param port the port */ public SwitchPort(long switchDPID, int port) { super(); this.switchDPID = switchDPID; this.port = port; this.errorStatus = null; } // *************** // Getters/Setters // *************** @JsonSerialize(using=DPIDSerializer.class) public long getSwitchDPID() { return switchDPID; } public int getPort() { return port; } public ErrorStatus getErrorStatus() { return errorStatus; } // ****** // Object // ****** @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((errorStatus == null) ? 0 : errorStatus.hashCode()); result = prime * result + port; result = prime * result + (int) (switchDPID ^ (switchDPID >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SwitchPort other = (SwitchPort) obj; if (errorStatus != other.errorStatus) return false; if (port != other.port) return false; if (switchDPID != other.switchDPID) return false; return true; } @Override public String toString() { return "SwitchPort [switchDPID=" + switchDPID + ", port=" + port + ", errorStatus=" + errorStatus + "]"; } }floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/0000775000175000017500000000000012041336206030335 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java0000664000175000017500000000766512041336206033405 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; /** * An index that maps key fields of an entity to device keys */ public abstract class DeviceIndex { /** * The key fields for this index */ protected EnumSet keyFields; /** * Construct a new device index using the provided key fields * @param keyFields the key fields to use */ public DeviceIndex(EnumSet keyFields) { super(); this.keyFields = keyFields; } /** * Find all device keys in the index that match the given entity * on all the key fields for this index * @param e the entity to search for * @return an iterator over device keys */ public abstract Iterator queryByEntity(Entity entity); /** * Get all device keys in the index. If certain devices exist * multiple times, then these devices may be returned multiple times * @return an iterator over device keys */ public abstract Iterator getAll(); /** * Attempt to update an index with the entities in the provided * {@link Device}. If the update fails because of a concurrent update, * will return false. * @param device the device to update * @param deviceKey the device key for the device * @return true if the update succeeded, false otherwise. */ public abstract boolean updateIndex(Device device, Long deviceKey); /** * Add a mapping from the given entity to the given device key. This * update will not fail because of a concurrent update * @param device the device to update * @param deviceKey the device key for the device */ public abstract void updateIndex(Entity entity, Long deviceKey); /** * Remove the entry for the given entity * @param entity the entity to remove */ public abstract void removeEntity(Entity entity); /** * Remove the given device key from the index for the given entity * @param entity the entity to search for * @param deviceKey the key to remove */ public abstract void removeEntity(Entity entity, Long deviceKey); /** * Remove the give device from the index only if this the collection * of others does not contain an entity that is identical on all the key * fields for this index. * @param entity the entity to search for * @param deviceKey the key to remove * @param others the others against which to check */ public void removeEntityIfNeeded(Entity entity, Long deviceKey, Collection others) { IndexedEntity ie = new IndexedEntity(keyFields, entity); for (Entity o : others) { IndexedEntity oio = new IndexedEntity(keyFields, o); if (oio.equals(ie)) return; } Iterator keyiter = this.queryByEntity(entity); while (keyiter.hasNext()) { Long key = keyiter.next(); if (key.equals(deviceKey)) { removeEntity(entity, deviceKey); break; } } } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java0000775000175000017500000020024012041336206034515 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.SingletonTask; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IEntityClassListener; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.devicemanager.IDeviceListener; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.web.DeviceRoutable; import net.floodlightcontroller.flowcache.IFlowReconcileListener; import net.floodlightcontroller.flowcache.IFlowReconcileService; import net.floodlightcontroller.flowcache.OFMatchReconcile; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.DHCP; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.ITopologyListener; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.util.MultiIterator; import static net.floodlightcontroller.devicemanager.internal. DeviceManagerImpl.DeviceUpdate.Change.*; import org.openflow.protocol.OFMatchWithSwDpid; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DeviceManager creates Devices based upon MAC addresses seen in the network. * It tracks any network addresses mapped to the Device, and its location * within the network. * @author readams */ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, ITopologyListener, IFloodlightModule, IEntityClassListener, IFlowReconcileListener, IInfoProvider, IHAListener { protected static Logger logger = LoggerFactory.getLogger(DeviceManagerImpl.class); protected IFloodlightProviderService floodlightProvider; protected ITopologyService topology; protected IStorageSourceService storageSource; protected IRestApiService restApi; protected IThreadPoolService threadPool; protected IFlowReconcileService flowReconcileMgr; /** * Time in milliseconds before entities will expire */ protected static final int ENTITY_TIMEOUT = 60*60*1000; /** * Time in seconds between cleaning up old entities/devices */ protected static final int ENTITY_CLEANUP_INTERVAL = 60*60; /** * This is the master device map that maps device IDs to {@link Device} * objects. */ protected ConcurrentHashMap deviceMap; /** * Counter used to generate device keys */ protected long deviceKeyCounter = 0; /** * Lock for incrementing the device key counter */ protected Object deviceKeyLock = new Object(); /** * This is the primary entity index that contains all entities */ protected DeviceUniqueIndex primaryIndex; /** * This stores secondary indices over the fields in the devices */ protected Map, DeviceIndex> secondaryIndexMap; /** * This map contains state for each of the {@ref IEntityClass} * that exist */ protected ConcurrentHashMap classStateMap; /** * This is the list of indices we want on a per-class basis */ protected Set> perClassIndices; /** * The entity classifier currently in use */ protected IEntityClassifierService entityClassifier; /** * Used to cache state about specific entity classes */ protected class ClassState { /** * The class index */ protected DeviceUniqueIndex classIndex; /** * This stores secondary indices over the fields in the device for the * class */ protected Map, DeviceIndex> secondaryIndexMap; /** * Allocate a new {@link ClassState} object for the class * @param clazz the class to use for the state */ public ClassState(IEntityClass clazz) { EnumSet keyFields = clazz.getKeyFields(); EnumSet primaryKeyFields = entityClassifier.getKeyFields(); boolean keyFieldsMatchPrimary = primaryKeyFields.equals(keyFields); if (!keyFieldsMatchPrimary) classIndex = new DeviceUniqueIndex(keyFields); secondaryIndexMap = new HashMap, DeviceIndex>(); for (EnumSet fields : perClassIndices) { secondaryIndexMap.put(fields, new DeviceMultiIndex(fields)); } } } /** * Device manager event listeners */ protected Set deviceListeners; /** * A device update event to be dispatched */ protected static class DeviceUpdate { public enum Change { ADD, DELETE, CHANGE; } /** * The affected device */ protected IDevice device; /** * The change that was made */ protected Change change; /** * If not added, then this is the list of fields changed */ protected EnumSet fieldsChanged; public DeviceUpdate(IDevice device, Change change, EnumSet fieldsChanged) { super(); this.device = device; this.change = change; this.fieldsChanged = fieldsChanged; } @Override public String toString() { String devIdStr = device.getEntityClass().getName() + "::" + device.getMACAddressString(); return "DeviceUpdate [device=" + devIdStr + ", change=" + change + ", fieldsChanged=" + fieldsChanged + "]"; } } /** * AttachmentPointComparator * * Compares two attachment points and returns the latest one. * It is assumed that the two attachment points are in the same * L2 domain. * * @author srini */ protected class AttachmentPointComparator implements Comparator { public AttachmentPointComparator() { super(); } @Override public int compare(AttachmentPoint oldAP, AttachmentPoint newAP) { //First compare based on L2 domain ID; long oldSw = oldAP.getSw(); short oldPort = oldAP.getPort(); long oldDomain = topology.getL2DomainId(oldSw); boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort); long newSw = newAP.getSw(); short newPort = newAP.getPort(); long newDomain = topology.getL2DomainId(newSw); boolean newBD = topology.isBroadcastDomainPort(newSw, newPort); if (oldDomain < newDomain) return -1; else if (oldDomain > newDomain) return 1; // We expect that the last seen of the new AP is higher than // old AP, if it is not, just reverse and send the negative // of the result. if (oldAP.getActiveSince() > newAP.getActiveSince()) return -compare(newAP, oldAP); long activeOffset = 0; if (!topology.isConsistent(oldSw, oldPort, newSw, newPort)) { if (!newBD && oldBD) { return -1; } if (newBD && oldBD) { activeOffset = AttachmentPoint.EXTERNAL_TO_EXTERNAL_TIMEOUT; } else if (newBD && !oldBD){ activeOffset = AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT; } } else { // The attachment point is consistent. activeOffset = AttachmentPoint.CONSISTENT_TIMEOUT; } if ((newAP.getActiveSince() > oldAP.getLastSeen() + activeOffset) || (newAP.getLastSeen() > oldAP.getLastSeen() + AttachmentPoint.INACTIVITY_INTERVAL)) { return -1; } return 1; } } /** * Comparator for sorting by cluster ID */ public AttachmentPointComparator apComparator; /** * Switch ports where attachment points shouldn't be learned */ private Set suppressAPs; /** * Periodic task to clean up expired entities */ public SingletonTask entityCleanupTask; // ********************* // IDeviceManagerService // ********************* @Override public IDevice getDevice(Long deviceKey) { return deviceMap.get(deviceKey); } @Override public IDevice findDevice(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) throws IllegalArgumentException { if (vlan != null && vlan.shortValue() <= 0) vlan = null; if (ipv4Address != null && ipv4Address == 0) ipv4Address = null; Entity e = new Entity(macAddress, vlan, ipv4Address, switchDPID, switchPort, null); if (!allKeyFieldsPresent(e, entityClassifier.getKeyFields())) { throw new IllegalArgumentException("Not all key fields specified." + " Required fields: " + entityClassifier.getKeyFields()); } return findDeviceByEntity(e); } @Override public IDevice findDestDevice(IDevice source, long macAddress, Short vlan, Integer ipv4Address) throws IllegalArgumentException { if (vlan != null && vlan.shortValue() <= 0) vlan = null; if (ipv4Address != null && ipv4Address == 0) ipv4Address = null; Entity e = new Entity(macAddress, vlan, ipv4Address, null, null, null); if (source == null || !allKeyFieldsPresent(e, source.getEntityClass().getKeyFields())) { throw new IllegalArgumentException("Not all key fields and/or " + " no source device specified. Required fields: " + entityClassifier.getKeyFields()); } return findDestByEntity(source, e); } @Override public Collection getAllDevices() { return Collections.unmodifiableCollection(deviceMap.values()); } @Override public void addIndex(boolean perClass, EnumSet keyFields) { if (perClass) { perClassIndices.add(keyFields); } else { secondaryIndexMap.put(keyFields, new DeviceMultiIndex(keyFields)); } } @Override public Iterator queryDevices(Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { DeviceIndex index = null; if (secondaryIndexMap.size() > 0) { EnumSet keys = getEntityKeys(macAddress, vlan, ipv4Address, switchDPID, switchPort); index = secondaryIndexMap.get(keys); } Iterator deviceIterator = null; if (index == null) { // Do a full table scan deviceIterator = deviceMap.values().iterator(); } else { // index lookup Entity entity = new Entity((macAddress == null ? 0 : macAddress), vlan, ipv4Address, switchDPID, switchPort, null); deviceIterator = new DeviceIndexInterator(this, index.queryByEntity(entity)); } DeviceIterator di = new DeviceIterator(deviceIterator, null, macAddress, vlan, ipv4Address, switchDPID, switchPort); return di; } @Override public Iterator queryClassDevices(IDevice reference, Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { IEntityClass entityClass = reference.getEntityClass(); ArrayList> iterators = new ArrayList>(); ClassState classState = getClassState(entityClass); DeviceIndex index = null; if (classState.secondaryIndexMap.size() > 0) { EnumSet keys = getEntityKeys(macAddress, vlan, ipv4Address, switchDPID, switchPort); index = classState.secondaryIndexMap.get(keys); } Iterator iter; if (index == null) { index = classState.classIndex; if (index == null) { // scan all devices return new DeviceIterator(deviceMap.values().iterator(), new IEntityClass[] { entityClass }, macAddress, vlan, ipv4Address, switchDPID, switchPort); } else { // scan the entire class iter = new DeviceIndexInterator(this, index.getAll()); } } else { // index lookup Entity entity = new Entity((macAddress == null ? 0 : macAddress), vlan, ipv4Address, switchDPID, switchPort, null); iter = new DeviceIndexInterator(this, index.queryByEntity(entity)); } iterators.add(iter); return new MultiIterator(iterators.iterator()); } protected Iterator getDeviceIteratorForQuery(Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { DeviceIndex index = null; if (secondaryIndexMap.size() > 0) { EnumSet keys = getEntityKeys(macAddress, vlan, ipv4Address, switchDPID, switchPort); index = secondaryIndexMap.get(keys); } Iterator deviceIterator = null; if (index == null) { // Do a full table scan deviceIterator = deviceMap.values().iterator(); } else { // index lookup Entity entity = new Entity((macAddress == null ? 0 : macAddress), vlan, ipv4Address, switchDPID, switchPort, null); deviceIterator = new DeviceIndexInterator(this, index.queryByEntity(entity)); } DeviceIterator di = new DeviceIterator(deviceIterator, null, macAddress, vlan, ipv4Address, switchDPID, switchPort); return di; } @Override public void addListener(IDeviceListener listener) { deviceListeners.add(listener); } // ************* // IInfoProvider // ************* @Override public Map getInfo(String type) { if (!"summary".equals(type)) return null; Map info = new HashMap(); info.put("# hosts", deviceMap.size()); return info; } // ****************** // IOFMessageListener // ****************** @Override public String getName() { return "devicemanager"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return ((type == OFType.PACKET_IN || type == OFType.FLOW_MOD) && name.equals("topology")); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx); default: break; } return Command.CONTINUE; } // *************** // IFlowReconcileListener // *************** @Override public Command reconcileFlows(ArrayList ofmRcList) { ListIterator iter = ofmRcList.listIterator(); while (iter.hasNext()) { OFMatchReconcile ofm = iter.next(); // Remove the STOPPed flow. if (Command.STOP == reconcileFlow(ofm)) { iter.remove(); } } if (ofmRcList.size() > 0) { return Command.CONTINUE; } else { return Command.STOP; } } protected Command reconcileFlow(OFMatchReconcile ofm) { // Extract source entity information Entity srcEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, true); if (srcEntity == null) return Command.STOP; // Find the device by source entity Device srcDevice = findDeviceByEntity(srcEntity); if (srcDevice == null) return Command.STOP; // Store the source device in the context fcStore.put(ofm.cntx, CONTEXT_SRC_DEVICE, srcDevice); // Find the device matching the destination from the entity // classes of the source. Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false); Device dstDevice = null; if (dstEntity != null) { dstDevice = findDestByEntity(srcDevice, dstEntity); if (dstDevice != null) fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice); } if (logger.isTraceEnabled()) { logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, " + "dstEntity={}, dstDev={}", new Object[] {ofm.ofmWithSwDpid.getOfMatch(), srcEntity, srcDevice, dstEntity, dstDevice } ); } return Command.CONTINUE; } // ***************** // IFloodlightModule // ***************** @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IDeviceService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IDeviceService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IStorageSourceService.class); l.add(ITopologyService.class); l.add(IRestApiService.class); l.add(IThreadPoolService.class); l.add(IFlowReconcileService.class); l.add(IEntityClassifierService.class); return l; } @Override public void init(FloodlightModuleContext fmc) { this.perClassIndices = new HashSet>(); addIndex(true, EnumSet.of(DeviceField.IPV4)); this.deviceListeners = new HashSet(); this.suppressAPs = Collections.synchronizedSet(new HashSet()); this.floodlightProvider = fmc.getServiceImpl(IFloodlightProviderService.class); this.storageSource = fmc.getServiceImpl(IStorageSourceService.class); this.topology = fmc.getServiceImpl(ITopologyService.class); this.restApi = fmc.getServiceImpl(IRestApiService.class); this.threadPool = fmc.getServiceImpl(IThreadPoolService.class); this.flowReconcileMgr = fmc.getServiceImpl(IFlowReconcileService.class); this.entityClassifier = fmc.getServiceImpl(IEntityClassifierService.class); } @Override public void startUp(FloodlightModuleContext fmc) { primaryIndex = new DeviceUniqueIndex(entityClassifier.getKeyFields()); secondaryIndexMap = new HashMap, DeviceIndex>(); deviceMap = new ConcurrentHashMap(); classStateMap = new ConcurrentHashMap(); apComparator = new AttachmentPointComparator(); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addHAListener(this); if (topology != null) topology.addListener(this); flowReconcileMgr.addFlowReconcileListener(this); entityClassifier.addListener(this); Runnable ecr = new Runnable() { @Override public void run() { cleanupEntities(); entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL, TimeUnit.SECONDS); } }; ScheduledExecutorService ses = threadPool.getScheduledExecutor(); entityCleanupTask = new SingletonTask(ses, ecr); entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL, TimeUnit.SECONDS); if (restApi != null) { restApi.addRestletRoutable(new DeviceRoutable()); } else { logger.debug("Could not instantiate REST API"); } } // *************** // IHAListener // *************** @Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case SLAVE: logger.debug("Resetting device state because of role change"); startUp(null); break; default: break; } } @Override public void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { // no-op } // **************** // Internal methods // **************** protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore. get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); // Extract source entity information Entity srcEntity = getSourceEntityFromPacket(eth, sw.getId(), pi.getInPort()); if (srcEntity == null) return Command.STOP; // Learn/lookup device information Device srcDevice = learnDeviceByEntity(srcEntity); if (srcDevice == null) return Command.STOP; // Store the source device in the context fcStore.put(cntx, CONTEXT_SRC_DEVICE, srcDevice); // Find the device matching the destination from the entity // classes of the source. Entity dstEntity = getDestEntityFromPacket(eth); Device dstDevice = null; if (dstEntity != null) { dstDevice = findDestByEntity(srcDevice, dstEntity); if (dstDevice != null) fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice); } if (logger.isTraceEnabled()) { logger.trace("Received PI: {} on switch {}, port {} *** eth={}" + " *** srcDev={} *** dstDev={} *** ", new Object[] { pi, sw.getStringId(), pi.getInPort(), eth, srcDevice, dstDevice }); } return Command.CONTINUE; } /** * Check whether the given attachment point is valid given the current * topology * @param switchDPID the DPID * @param switchPort the port * @return true if it's a valid attachment point */ public boolean isValidAttachmentPoint(long switchDPID, int switchPort) { if (topology.isAttachmentPointPort(switchDPID, (short)switchPort) == false) return false; if (suppressAPs.contains(new SwitchPort(switchDPID, switchPort))) return false; return true; } /** * Get IP address from packet if the packet is either an ARP * or a DHCP packet * @param eth * @param dlAddr * @return */ private int getSrcNwAddr(Ethernet eth, long dlAddr) { if (eth.getPayload() instanceof ARP) { ARP arp = (ARP) eth.getPayload(); if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) && (Ethernet.toLong(arp.getSenderHardwareAddress()) == dlAddr)) { return IPv4.toIPv4Address(arp.getSenderProtocolAddress()); } } else if (eth.getPayload() instanceof IPv4) { IPv4 ipv4 = (IPv4) eth.getPayload(); if (ipv4.getPayload() instanceof UDP) { UDP udp = (UDP)ipv4.getPayload(); if (udp.getPayload() instanceof DHCP) { DHCP dhcp = (DHCP)udp.getPayload(); if (dhcp.getOpCode() == DHCP.OPCODE_REPLY) { return ipv4.getSourceAddress(); } } } } return 0; } /** * Parse an entity from an {@link Ethernet} packet. * @param eth the packet to parse * @param sw the switch on which the packet arrived * @param pi the original packetin * @return the entity from the packet */ protected Entity getSourceEntityFromPacket(Ethernet eth, long swdpid, int port) { byte[] dlAddrArr = eth.getSourceMACAddress(); long dlAddr = Ethernet.toLong(dlAddrArr); // Ignore broadcast/multicast source if ((dlAddrArr[0] & 0x1) != 0) return null; short vlan = eth.getVlanID(); int nwSrc = getSrcNwAddr(eth, dlAddr); return new Entity(dlAddr, ((vlan >= 0) ? vlan : null), ((nwSrc != 0) ? nwSrc : null), swdpid, port, new Date()); } /** * Get a (partial) entity for the destination from the packet. * @param eth * @return */ protected Entity getDestEntityFromPacket(Ethernet eth) { byte[] dlAddrArr = eth.getDestinationMACAddress(); long dlAddr = Ethernet.toLong(dlAddrArr); short vlan = eth.getVlanID(); int nwDst = 0; // Ignore broadcast/multicast destination if ((dlAddrArr[0] & 0x1) != 0) return null; if (eth.getPayload() instanceof IPv4) { IPv4 ipv4 = (IPv4) eth.getPayload(); nwDst = ipv4.getDestinationAddress(); } return new Entity(dlAddr, ((vlan >= 0) ? vlan : null), ((nwDst != 0) ? nwDst : null), null, null, null); } /** * Parse an entity from an OFMatchWithSwDpid. * @param ofmWithSwDpid * @return the entity from the packet */ private Entity getEntityFromFlowMod(OFMatchWithSwDpid ofmWithSwDpid, boolean isSource) { byte[] dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerSource(); int nwSrc = ofmWithSwDpid.getOfMatch().getNetworkSource(); if (!isSource) { dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerDestination(); nwSrc = ofmWithSwDpid.getOfMatch().getNetworkDestination(); } long dlAddr = Ethernet.toLong(dlAddrArr); // Ignore broadcast/multicast source if ((dlAddrArr[0] & 0x1) != 0) return null; Long swDpid = null; Short inPort = null; if (isSource) { swDpid = ofmWithSwDpid.getSwitchDataPathId(); inPort = ofmWithSwDpid.getOfMatch().getInputPort(); } boolean learnap = true; if (swDpid == null || inPort == null || !isValidAttachmentPoint(swDpid, inPort)) { // If this is an internal port or we otherwise don't want // to learn on these ports. In the future, we should // handle this case by labeling flows with something that // will give us the entity class. For now, we'll do our // best assuming attachment point information isn't used // as a key field. learnap = false; } short vlan = ofmWithSwDpid.getOfMatch().getDataLayerVirtualLan(); return new Entity(dlAddr, ((vlan >= 0) ? vlan : null), ((nwSrc != 0) ? nwSrc : null), (learnap ? swDpid : null), (learnap ? (int)inPort : null), new Date()); } /** * Look up a {@link Device} based on the provided {@link Entity}. We first * check the primary index. If we do not find an entry there we classify * the device into its IEntityClass and query the classIndex. * This implies that all key field of the current IEntityClassifier must * be present in the entity for the lookup to succeed! * @param entity the entity to search for * @return The {@link Device} object if found */ protected Device findDeviceByEntity(Entity entity) { // Look up the fully-qualified entity to see if it already // exists in the primary entity index. Long deviceKey = primaryIndex.findByEntity(entity); IEntityClass entityClass = null; if (deviceKey == null) { // If the entity does not exist in the primary entity index, // use the entity classifier for find the classes for the // entity. Look up the entity in the returned class' // class entity index. entityClass = entityClassifier.classifyEntity(entity); if (entityClass == null) { return null; } ClassState classState = getClassState(entityClass); if (classState.classIndex != null) { deviceKey = classState.classIndex.findByEntity(entity); } } if (deviceKey == null) return null; return deviceMap.get(deviceKey); } /** * Get a destination device using entity fields that corresponds with * the given source device. The source device is important since * there could be ambiguity in the destination device without the * attachment point information. * @param source the source device. The returned destination will be * in the same entity class as the source. * @param dstEntity the entity to look up * @return an {@link Device} or null if no device is found. */ protected Device findDestByEntity(IDevice source, Entity dstEntity) { // Look up the fully-qualified entity to see if it // exists in the primary entity index Long deviceKey = primaryIndex.findByEntity(dstEntity); if (deviceKey == null) { // This could happen because: // 1) no destination known, or a broadcast destination // 2) if we have attachment point key fields since // attachment point information isn't available for // destination devices. // For the second case, we'll need to match up the // destination device with the class of the source // device. ClassState classState = getClassState(source.getEntityClass()); if (classState.classIndex == null) { return null; } deviceKey = classState.classIndex.findByEntity(dstEntity); } if (deviceKey == null) return null; return deviceMap.get(deviceKey); } /** * Look up a {@link Device} within a particular entity class based on * the provided {@link Entity}. * @param clazz the entity class to search for the entity * @param entity the entity to search for * @return The {@link Device} object if found private Device findDeviceInClassByEntity(IEntityClass clazz, Entity entity) { // XXX - TODO throw new UnsupportedOperationException(); } */ /** * Look up a {@link Device} based on the provided {@link Entity}. Also * learns based on the new entity, and will update existing devices as * required. * * @param entity the {@link Entity} * @return The {@link Device} object if found */ protected Device learnDeviceByEntity(Entity entity) { ArrayList deleteQueue = null; LinkedList deviceUpdates = null; Device device = null; // we may need to restart the learning process if we detect // concurrent modification. Note that we ensure that at least // one thread should always succeed so we don't get into infinite // starvation loops while (true) { deviceUpdates = null; // Look up the fully-qualified entity to see if it already // exists in the primary entity index. Long deviceKey = primaryIndex.findByEntity(entity); IEntityClass entityClass = null; if (deviceKey == null) { // If the entity does not exist in the primary entity index, // use the entity classifier for find the classes for the // entity. Look up the entity in the returned class' // class entity index. entityClass = entityClassifier.classifyEntity(entity); if (entityClass == null) { // could not classify entity. No device return null; } ClassState classState = getClassState(entityClass); if (classState.classIndex != null) { deviceKey = classState.classIndex.findByEntity(entity); } } if (deviceKey != null) { // If the primary or secondary index contains the entity // use resulting device key to look up the device in the // device map, and use the referenced Device below. device = deviceMap.get(deviceKey); if (device == null) throw new IllegalStateException("Corrupted device index"); } else { // If the secondary index does not contain the entity, // create a new Device object containing the entity, and // generate a new device ID. However, we first check if // the entity is allowed (e.g., for spoofing protection) if (!isEntityAllowed(entity, entityClass)) { logger.info("PacketIn is not allowed {} {}", entityClass.getName(), entity); return null; } synchronized (deviceKeyLock) { deviceKey = Long.valueOf(deviceKeyCounter++); } device = allocateDevice(deviceKey, entity, entityClass); if (logger.isDebugEnabled()) { logger.debug("New device created: {} deviceKey={}, entity={}", new Object[]{device, deviceKey, entity}); } // Add the new device to the primary map with a simple put deviceMap.put(deviceKey, device); // update indices if (!updateIndices(device, deviceKey)) { if (deleteQueue == null) deleteQueue = new ArrayList(); deleteQueue.add(deviceKey); continue; } updateSecondaryIndices(entity, entityClass, deviceKey); // generate new device update deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(device, ADD, null)); break; } if (!isEntityAllowed(entity, device.getEntityClass())) { logger.info("PacketIn is not allowed {} {}", device.getEntityClass().getName(), entity); return null; } int entityindex = -1; if ((entityindex = device.entityIndex(entity)) >= 0) { // update timestamp on the found entity Date lastSeen = entity.getLastSeenTimestamp(); if (lastSeen == null) lastSeen = new Date(); device.entities[entityindex].setLastSeenTimestamp(lastSeen); if (device.entities[entityindex].getSwitchDPID() != null && device.entities[entityindex].getSwitchPort() != null) { long sw = device.entities[entityindex].getSwitchDPID(); short port = device.entities[entityindex].getSwitchPort().shortValue(); boolean moved = device.updateAttachmentPoint(sw, port, lastSeen.getTime()); if (moved) { sendDeviceMovedNotification(device); if (logger.isTraceEnabled()) { logger.trace("Device moved: attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } else { if (logger.isTraceEnabled()) { logger.trace("Device attachment point NOT updated: " + "attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } } break; } else { boolean moved = false; Device newDevice = allocateDevice(device, entity); if (entity.getSwitchDPID() != null && entity.getSwitchPort() != null) { moved = newDevice.updateAttachmentPoint(entity.getSwitchDPID(), entity.getSwitchPort().shortValue(), entity.getLastSeenTimestamp().getTime()); } // generate updates EnumSet changedFields = findChangedFields(device, entity); if (changedFields.size() > 0) deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(newDevice, CHANGE, changedFields)); // update the device map with a replace call boolean res = deviceMap.replace(deviceKey, device, newDevice); // If replace returns false, restart the process from the // beginning (this implies another thread concurrently // modified this Device). if (!res) continue; device = newDevice; // update indices if (!updateIndices(device, deviceKey)) { continue; } updateSecondaryIndices(entity, device.getEntityClass(), deviceKey); if (moved) { sendDeviceMovedNotification(device); if (logger.isDebugEnabled()) { logger.debug("Device moved: attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } else { if (logger.isDebugEnabled()) { logger.debug("Device attachment point updated: " + "attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } break; } } if (deleteQueue != null) { for (Long l : deleteQueue) { Device dev = deviceMap.get(l); this.deleteDevice(dev); // generate new device update deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(dev, DELETE, null)); } } processUpdates(deviceUpdates); return device; } protected boolean isEntityAllowed(Entity entity, IEntityClass entityClass) { return true; } protected EnumSet findChangedFields(Device device, Entity newEntity) { EnumSet changedFields = EnumSet.of(DeviceField.IPV4, DeviceField.VLAN, DeviceField.SWITCH); if (newEntity.getIpv4Address() == null) changedFields.remove(DeviceField.IPV4); if (newEntity.getVlan() == null) changedFields.remove(DeviceField.VLAN); if (newEntity.getSwitchDPID() == null || newEntity.getSwitchPort() == null) changedFields.remove(DeviceField.SWITCH); if (changedFields.size() == 0) return changedFields; for (Entity entity : device.getEntities()) { if (newEntity.getIpv4Address() == null || (entity.getIpv4Address() != null && entity.getIpv4Address().equals(newEntity.getIpv4Address()))) changedFields.remove(DeviceField.IPV4); if (newEntity.getVlan() == null || (entity.getVlan() != null && entity.getVlan().equals(newEntity.getVlan()))) changedFields.remove(DeviceField.VLAN); if (newEntity.getSwitchDPID() == null || newEntity.getSwitchPort() == null || (entity.getSwitchDPID() != null && entity.getSwitchPort() != null && entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) && entity.getSwitchPort().equals(newEntity.getSwitchPort()))) changedFields.remove(DeviceField.SWITCH); } return changedFields; } /** * Send update notifications to listeners * @param updates the updates to process. */ protected void processUpdates(Queue updates) { if (updates == null) return; DeviceUpdate update = null; while (null != (update = updates.poll())) { if (logger.isTraceEnabled()) { logger.trace("Dispatching device update: {}", update); } for (IDeviceListener listener : deviceListeners) { switch (update.change) { case ADD: listener.deviceAdded(update.device); break; case DELETE: listener.deviceRemoved(update.device); break; case CHANGE: for (DeviceField field : update.fieldsChanged) { switch (field) { case IPV4: listener.deviceIPV4AddrChanged(update.device); break; case SWITCH: case PORT: //listener.deviceMoved(update.device); break; case VLAN: listener.deviceVlanChanged(update.device); break; default: logger.debug("Unknown device field changed {}", update.fieldsChanged.toString()); break; } } break; } } } } /** * Check if the entity e has all the keyFields set. Returns false if not * @param e entity to check * @param keyFields the key fields to check e against * @return */ protected boolean allKeyFieldsPresent(Entity e, EnumSet keyFields) { for (DeviceField f : keyFields) { switch (f) { case MAC: // MAC address is always present break; case IPV4: if (e.ipv4Address == null) return false; break; case SWITCH: if (e.switchDPID == null) return false; break; case PORT: if (e.switchPort == null) return false; break; case VLAN: // FIXME: vlan==null is ambiguous: it can mean: not present // or untagged //if (e.vlan == null) return false; break; default: // we should never get here. unless somebody extended // DeviceFields throw new IllegalStateException(); } } return true; } private LinkedList updateUpdates(LinkedList list, DeviceUpdate update) { if (update == null) return list; if (list == null) list = new LinkedList(); list.add(update); return list; } /** * Get the secondary index for a class. Will return null if the * secondary index was created concurrently in another thread. * @param clazz the class for the index * @return */ private ClassState getClassState(IEntityClass clazz) { ClassState classState = classStateMap.get(clazz.getName()); if (classState != null) return classState; classState = new ClassState(clazz); ClassState r = classStateMap.putIfAbsent(clazz.getName(), classState); if (r != null) { // concurrent add return r; } return classState; } /** * Update both the primary and class indices for the provided device. * If the update fails because of an concurrent update, will return false. * @param device the device to update * @param deviceKey the device key for the device * @return true if the update succeeded, false otherwise. */ private boolean updateIndices(Device device, Long deviceKey) { if (!primaryIndex.updateIndex(device, deviceKey)) { return false; } IEntityClass entityClass = device.getEntityClass(); ClassState classState = getClassState(entityClass); if (classState.classIndex != null) { if (!classState.classIndex.updateIndex(device, deviceKey)) return false; } return true; } /** * Update the secondary indices for the given entity and associated * entity classes * @param entity the entity to update * @param entityClass the entity class for the entity * @param deviceKey the device key to set up */ private void updateSecondaryIndices(Entity entity, IEntityClass entityClass, Long deviceKey) { for (DeviceIndex index : secondaryIndexMap.values()) { index.updateIndex(entity, deviceKey); } ClassState state = getClassState(entityClass); for (DeviceIndex index : state.secondaryIndexMap.values()) { index.updateIndex(entity, deviceKey); } } // ********************* // IEntityClassListener // ********************* @Override public void entityClassChanged (Set entityClassNames) { /* iterate through the devices, reclassify the devices that belong * to these entity class names */ Iterator diter = deviceMap.values().iterator(); while (diter.hasNext()) { Device d = diter.next(); if (d.getEntityClass() == null || entityClassNames.contains(d.getEntityClass().getName())) reclassifyDevice(d); } } /** * Clean up expired entities/devices */ protected void cleanupEntities () { Calendar c = Calendar.getInstance(); c.add(Calendar.MILLISECOND, -ENTITY_TIMEOUT); Date cutoff = c.getTime(); ArrayList toRemove = new ArrayList(); ArrayList toKeep = new ArrayList(); Iterator diter = deviceMap.values().iterator(); LinkedList deviceUpdates = new LinkedList(); while (diter.hasNext()) { Device d = diter.next(); while (true) { deviceUpdates.clear(); toRemove.clear(); toKeep.clear(); for (Entity e : d.getEntities()) { if (e.getLastSeenTimestamp() != null && 0 > e.getLastSeenTimestamp().compareTo(cutoff)) { // individual entity needs to be removed toRemove.add(e); } else { toKeep.add(e); } } if (toRemove.size() == 0) { break; } for (Entity e : toRemove) { removeEntity(e, d.getEntityClass(), d.deviceKey, toKeep); } if (toKeep.size() > 0) { Device newDevice = allocateDevice(d.getDeviceKey(), d.oldAPs, d.attachmentPoints, toKeep, d.entityClass); EnumSet changedFields = EnumSet.noneOf(DeviceField.class); for (Entity e : toRemove) { changedFields.addAll(findChangedFields(newDevice, e)); } if (changedFields.size() > 0) deviceUpdates.add(new DeviceUpdate(d, CHANGE, changedFields)); if (!deviceMap.replace(newDevice.getDeviceKey(), d, newDevice)) { // concurrent modification; try again // need to use device that is the map now for the next // iteration d = deviceMap.get(d.getDeviceKey()); if (null != d) continue; } } else { deviceUpdates.add(new DeviceUpdate(d, DELETE, null)); if (!deviceMap.remove(d.getDeviceKey(), d)) // concurrent modification; try again // need to use device that is the map now for the next // iteration d = deviceMap.get(d.getDeviceKey()); if (null != d) continue; } processUpdates(deviceUpdates); break; } } } protected void removeEntity(Entity removed, IEntityClass entityClass, Long deviceKey, Collection others) { for (DeviceIndex index : secondaryIndexMap.values()) { index.removeEntityIfNeeded(removed, deviceKey, others); } ClassState classState = getClassState(entityClass); for (DeviceIndex index : classState.secondaryIndexMap.values()) { index.removeEntityIfNeeded(removed, deviceKey, others); } primaryIndex.removeEntityIfNeeded(removed, deviceKey, others); if (classState.classIndex != null) { classState.classIndex.removeEntityIfNeeded(removed, deviceKey, others); } } /** * method to delete a given device, remove all entities first and then * finally delete the device itself. * @param device */ protected void deleteDevice(Device device) { ArrayList emptyToKeep = new ArrayList(); for (Entity entity : device.getEntities()) { this.removeEntity(entity, device.getEntityClass(), device.getDeviceKey(), emptyToKeep); } if (!deviceMap.remove(device.getDeviceKey(), device)) { if (logger.isDebugEnabled()) logger.debug("device map does not have this device -" + device.toString()); } } private EnumSet getEntityKeys(Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { // FIXME: vlan==null is a valid search. Need to handle this // case correctly. Note that the code will still work correctly. // But we might do a full device search instead of using an index. EnumSet keys = EnumSet.noneOf(DeviceField.class); if (macAddress != null) keys.add(DeviceField.MAC); if (vlan != null) keys.add(DeviceField.VLAN); if (ipv4Address != null) keys.add(DeviceField.IPV4); if (switchDPID != null) keys.add(DeviceField.SWITCH); if (switchPort != null) keys.add(DeviceField.PORT); return keys; } protected Iterator queryClassByEntity(IEntityClass clazz, EnumSet keyFields, Entity entity) { ClassState classState = getClassState(clazz); DeviceIndex index = classState.secondaryIndexMap.get(keyFields); if (index == null) return Collections.emptySet().iterator(); return new DeviceIndexInterator(this, index.queryByEntity(entity)); } protected Device allocateDevice(Long deviceKey, Entity entity, IEntityClass entityClass) { return new Device(this, deviceKey, entity, entityClass); } // TODO: FIX THIS. protected Device allocateDevice(Long deviceKey, List aps, List trueAPs, Collection entities, IEntityClass entityClass) { return new Device(this, deviceKey, aps, trueAPs, entities, entityClass); } protected Device allocateDevice(Device device, Entity entity) { return new Device(device, entity); } protected Device allocateDevice(Device device, Set entities) { List newPossibleAPs = new ArrayList(); List newAPs = new ArrayList(); for (Entity entity : entities) { if (entity.switchDPID != null && entity.switchPort != null) { AttachmentPoint aP = new AttachmentPoint(entity.switchDPID.longValue(), entity.switchPort.shortValue(), 0); newPossibleAPs.add(aP); } } if (device.attachmentPoints != null) { for (AttachmentPoint oldAP : device.attachmentPoints) { if (newPossibleAPs.contains(oldAP)) { newAPs.add(oldAP); } } } if (newAPs.isEmpty()) newAPs = null; Device d = new Device(this, device.getDeviceKey(),newAPs, null, entities, device.getEntityClass()); d.updateAttachmentPoint(); return d; } @Override public void addSuppressAPs(long swId, short port) { suppressAPs.add(new SwitchPort(swId, port)); } @Override public void removeSuppressAPs(long swId, short port) { suppressAPs.remove(new SwitchPort(swId, port)); } /** * Topology listener method. */ @Override public void topologyChanged() { Iterator diter = deviceMap.values().iterator(); List updateList = topology.getLastLinkUpdates(); if (updateList != null) { if (logger.isTraceEnabled()) { for(LDUpdate update: updateList) { logger.trace("Topo update: {}", update); } } } while (diter.hasNext()) { Device d = diter.next(); if (d.updateAttachmentPoint()) { if (logger.isDebugEnabled()) { logger.debug("Attachment point changed for device: {}", d); } sendDeviceMovedNotification(d); } } } /** * Send update notifications to listeners * @param updates the updates to process. */ protected void sendDeviceMovedNotification(Device d) { for (IDeviceListener listener : deviceListeners) { listener.deviceMoved(d); } } /** * this method will reclassify and reconcile a device - possibilities * are - create new device(s), remove entities from this device. If the * device entity class did not change then it returns false else true. * @param device */ protected boolean reclassifyDevice(Device device) { // first classify all entities of this device if (device == null) { logger.debug("In reclassify for null device"); return false; } boolean needToReclassify = false; for (Entity entity : device.entities) { IEntityClass entityClass = this.entityClassifier.classifyEntity(entity); if (entityClass == null || device.getEntityClass() == null) { needToReclassify = true; break; } if (!entityClass.getName(). equals(device.getEntityClass().getName())) { needToReclassify = true; break; } } if (needToReclassify == false) { return false; } LinkedList deviceUpdates = new LinkedList(); // delete this device and then re-learn all the entities this.deleteDevice(device); deviceUpdates.add(new DeviceUpdate(device, DeviceUpdate.Change.DELETE, null)); if (!deviceUpdates.isEmpty()) processUpdates(deviceUpdates); for (Entity entity: device.entities ) { this.learnDeviceByEntity(entity); } return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java0000664000175000017500000000702212041336206034303 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author Srini */ package net.floodlightcontroller.devicemanager.internal; public class AttachmentPoint { long sw; short port; long activeSince; long lastSeen; // Timeout for moving attachment points from OF/broadcast // domain to another. public static final long INACTIVITY_INTERVAL = 30000; // 30 seconds public static final long EXTERNAL_TO_EXTERNAL_TIMEOUT = 5000; // 5 seconds public static final long OPENFLOW_TO_EXTERNAL_TIMEOUT = 30000; // 30 seconds public static final long CONSISTENT_TIMEOUT = 30000; // 30 seconds public AttachmentPoint(long sw, short port, long activeSince, long lastSeen) { this.sw = sw; this.port = port; this.activeSince = activeSince; this.lastSeen = lastSeen; } public AttachmentPoint(long sw, short port, long lastSeen) { this.sw = sw; this.port = port; this.lastSeen = lastSeen; this.activeSince = lastSeen; } public AttachmentPoint(AttachmentPoint ap) { this.sw = ap.sw; this.port = ap.port; this.activeSince = ap.activeSince; this.lastSeen = ap.lastSeen; } public long getSw() { return sw; } public void setSw(long sw) { this.sw = sw; } public short getPort() { return port; } public void setPort(short port) { this.port = port; } public long getActiveSince() { return activeSince; } public void setActiveSince(long activeSince) { this.activeSince = activeSince; } public long getLastSeen() { return lastSeen; } public void setLastSeen(long lastSeen) { if (this.lastSeen + INACTIVITY_INTERVAL < lastSeen) this.activeSince = lastSeen; if (this.lastSeen < lastSeen) this.lastSeen = lastSeen; } /** * Hash is generated using only switch and port */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + port; result = prime * result + (int) (sw ^ (sw >>> 32)); return result; } /** * Compares only the switch and port */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AttachmentPoint other = (AttachmentPoint) obj; if (port != other.port) return false; if (sw != other.sw) return false; return true; } @Override public String toString() { return "AttachmentPoint [sw=" + sw + ", port=" + port + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java0000664000175000017500000000706212041336206034563 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; /** * An index that maps key fields of an entity uniquely to a device key */ public class DeviceUniqueIndex extends DeviceIndex { /** * The index */ private ConcurrentHashMap index; /** * Construct a new device index using the provided key fields * @param keyFields the key fields to use */ public DeviceUniqueIndex(EnumSet keyFields) { super(keyFields); index = new ConcurrentHashMap(); } // *********** // DeviceIndex // *********** @Override public Iterator queryByEntity(Entity entity) { final Long deviceKey = findByEntity(entity); if (deviceKey != null) return Collections.singleton(deviceKey).iterator(); return Collections.emptySet().iterator(); } @Override public Iterator getAll() { return index.values().iterator(); } @Override public boolean updateIndex(Device device, Long deviceKey) { for (Entity e : device.entities) { IndexedEntity ie = new IndexedEntity(keyFields, e); if (!ie.hasNonNullKeys()) continue; Long ret = index.putIfAbsent(ie, deviceKey); if (ret != null && !ret.equals(deviceKey)) { // If the return value is non-null, then fail the insert // (this implies that a device using this entity has // already been created in another thread). return false; } } return true; } @Override public void updateIndex(Entity entity, Long deviceKey) { IndexedEntity ie = new IndexedEntity(keyFields, entity); if (!ie.hasNonNullKeys()) return; index.put(ie, deviceKey); } @Override public void removeEntity(Entity entity) { IndexedEntity ie = new IndexedEntity(keyFields, entity); index.remove(ie); } @Override public void removeEntity(Entity entity, Long deviceKey) { IndexedEntity ie = new IndexedEntity(keyFields, entity); index.remove(ie, deviceKey); } // ************** // Public Methods // ************** /** * Look up a {@link Device} based on the provided {@link Entity}. * @param entity the entity to search for * @return The key for the {@link Device} object if found */ public Long findByEntity(Entity entity) { IndexedEntity ie = new IndexedEntity(keyFields, entity); Long deviceKey = index.get(ie); if (deviceKey == null) return null; return deviceKey; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java0000664000175000017500000000775312041336206034125 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Arrays; import java.util.Iterator; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.util.FilterIterator; /** * An iterator for handling device queries */ public class DeviceIterator extends FilterIterator { private IEntityClass[] entityClasses; private Long macAddress; private Short vlan; private Integer ipv4Address; private Long switchDPID; private Integer switchPort; /** * Construct a new device iterator over the key fields * @param subIterator an iterator over the full data structure to scan * @param entityClasses the entity classes to search for * @param macAddress The MAC address * @param vlan the VLAN * @param ipv4Address the ipv4 address * @param switchDPID the switch DPID * @param switchPort the switch port */ public DeviceIterator(Iterator subIterator, IEntityClass[] entityClasses, Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { super(subIterator); this.entityClasses = entityClasses; this.subIterator = subIterator; this.macAddress = macAddress; this.vlan = vlan; this.ipv4Address = ipv4Address; this.switchDPID = switchDPID; this.switchPort = switchPort; } @Override protected boolean matches(Device value) { boolean match; if (entityClasses != null) { IEntityClass clazz = value.getEntityClass(); if (clazz == null) return false; match = false; for (IEntityClass entityClass : entityClasses) { if (clazz.equals(entityClass)) { match = true; break; } } if (!match) return false; } if (macAddress != null) { if (macAddress.longValue() != value.getMACAddress()) return false; } if (vlan != null) { Short[] vlans = value.getVlanId(); if (Arrays.binarySearch(vlans, vlan) < 0) return false; } if (ipv4Address != null) { Integer[] ipv4Addresses = value.getIPv4Addresses(); if (Arrays.binarySearch(ipv4Addresses, ipv4Address) < 0) return false; } if (switchDPID != null || switchPort != null) { SwitchPort[] sps = value.getAttachmentPoints(); if (sps == null) return false; match = false; for (SwitchPort sp : sps) { if (switchDPID != null) { if (switchDPID.longValue() != sp.getSwitchDPID()) return false; } if (switchPort != null) { if (switchPort.intValue() != sp.getPort()) return false; } match = true; break; } if (!match) return false; } return true; } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.javafloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifie0000664000175000017500000001036612041336206034672 0ustar jamespagejamespage/** * Copyright 2011,2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IEntityClassListener; import net.floodlightcontroller.devicemanager.IEntityClassifierService; /** * This is a default entity classifier that simply classifies all * entities into a fixed entity class, with key fields of MAC and VLAN. * @author readams */ public class DefaultEntityClassifier implements IEntityClassifierService, IFloodlightModule { /** * A default fixed entity class */ protected static class DefaultEntityClass implements IEntityClass { String name; public DefaultEntityClass(String name) { this.name = name; } @Override public EnumSet getKeyFields() { return keyFields; } @Override public String getName() { return name; } } protected static EnumSet keyFields; static { keyFields = EnumSet.of(DeviceField.MAC, DeviceField.VLAN); } protected static DefaultEntityClass entityClass = new DefaultEntityClass("DefaultEntityClass"); @Override public IEntityClass classifyEntity(Entity entity) { return entityClass; } @Override public IEntityClass reclassifyEntity(IDevice curDevice, Entity entity) { return entityClass; } @Override public void deviceUpdate(IDevice oldDevice, Collection newDevices) { // no-op } @Override public EnumSet getKeyFields() { return keyFields; } @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IEntityClassifierService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IEntityClassifierService.class, this); return m; } @Override public Collection> getModuleDependencies() { // No dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { // no-op } @Override public void startUp(FloodlightModuleContext context) { // no-op } @Override public void addListener(IEntityClassListener listener) { // no-op } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java0000775000175000017500000006053212041336206032410 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeSet; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.web.DeviceSerializer; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.topology.ITopologyService; /** * Concrete implementation of {@link IDevice} * @author readams */ @JsonSerialize(using=DeviceSerializer.class) public class Device implements IDevice { protected static Logger log = LoggerFactory.getLogger(Device.class); protected Long deviceKey; protected DeviceManagerImpl deviceManager; protected Entity[] entities; protected IEntityClass entityClass; protected String macAddressString; /** * These are the old attachment points for the device that were * valid no more than INACTIVITY_TIME ago. */ protected List oldAPs; /** * The current attachment points for the device. */ protected List attachmentPoints; // ************ // Constructors // ************ /** * Create a device from an entities * @param deviceManager the device manager for this device * @param deviceKey the unique identifier for this device object * @param entity the initial entity for the device * @param entityClass the entity classes associated with the entity */ public Device(DeviceManagerImpl deviceManager, Long deviceKey, Entity entity, IEntityClass entityClass) { this.deviceManager = deviceManager; this.deviceKey = deviceKey; this.entities = new Entity[] {entity}; this.macAddressString = HexString.toHexString(entity.getMacAddress(), 6); this.entityClass = entityClass; Arrays.sort(this.entities); this.oldAPs = null; this.attachmentPoints = null; if (entity.getSwitchDPID() != null && entity.getSwitchPort() != null){ long sw = entity.getSwitchDPID(); short port = entity.getSwitchPort().shortValue(); if (deviceManager.isValidAttachmentPoint(sw, port)) { AttachmentPoint ap; ap = new AttachmentPoint(sw, port, entity.getLastSeenTimestamp().getTime()); this.attachmentPoints = new ArrayList(); this.attachmentPoints.add(ap); } } } /** * Create a device from a set of entities * @param deviceManager the device manager for this device * @param deviceKey the unique identifier for this device object * @param entities the initial entities for the device * @param entityClass the entity class associated with the entities */ public Device(DeviceManagerImpl deviceManager, Long deviceKey, Collection oldAPs, Collection attachmentPoints, Collection entities, IEntityClass entityClass) { this.deviceManager = deviceManager; this.deviceKey = deviceKey; this.entities = entities.toArray(new Entity[entities.size()]); this.oldAPs = null; this.attachmentPoints = null; if (oldAPs != null) { this.oldAPs = new ArrayList(oldAPs); } if (attachmentPoints != null) { this.attachmentPoints = new ArrayList(attachmentPoints); } this.macAddressString = HexString.toHexString(this.entities[0].getMacAddress(), 6); this.entityClass = entityClass; Arrays.sort(this.entities); } /** * Construct a new device consisting of the entities from the old device * plus an additional entity * @param device the old device object * @param newEntity the entity to add. newEntity must be have the same * entity class as device */ public Device(Device device, Entity newEntity) { this.deviceManager = device.deviceManager; this.deviceKey = device.deviceKey; this.entities = Arrays.copyOf(device.entities, device.entities.length + 1); this.entities[this.entities.length - 1] = newEntity; Arrays.sort(this.entities); this.oldAPs = null; if (device.oldAPs != null) { this.oldAPs = new ArrayList(device.oldAPs); } this.attachmentPoints = null; if (device.attachmentPoints != null) { this.attachmentPoints = new ArrayList(device.attachmentPoints); } this.macAddressString = HexString.toHexString(this.entities[0].getMacAddress(), 6); this.entityClass = device.entityClass; } /** * Given a list of attachment points (apList), the procedure would return * a map of attachment points for each L2 domain. L2 domain id is the key. * @param apList * @return */ private Map getAPMap(List apList) { if (apList == null) return null; ITopologyService topology = deviceManager.topology; // Get the old attachment points and sort them. ListoldAP = new ArrayList(); if (apList != null) oldAP.addAll(apList); // Remove invalid attachment points before sorting. ListtempAP = new ArrayList(); for(AttachmentPoint ap: oldAP) { if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())){ tempAP.add(ap); } } oldAP = tempAP; Collections.sort(oldAP, deviceManager.apComparator); // Map of attachment point by L2 domain Id. Map apMap = new HashMap(); for(int i=0; iapList) { List expiredAPs = new ArrayList(); if (apList == null) return false; for(AttachmentPoint ap: apList) { if (ap.getLastSeen() + AttachmentPoint.INACTIVITY_INTERVAL < System.currentTimeMillis()) expiredAPs.add(ap); } if (expiredAPs.size() > 0) { apList.removeAll(expiredAPs); return true; } else return false; } /** * Get a list of duplicate attachment points, given a list of old attachment * points and one attachment point per L2 domain. Given a true attachment * point in the L2 domain, say trueAP, another attachment point in the * same L2 domain, say ap, is duplicate if: * 1. ap is inconsistent with trueAP, and * 2. active time of ap is after that of trueAP; and * 3. last seen time of ap is within the last INACTIVITY_INTERVAL * @param oldAPList * @param apMap * @return */ List getDuplicateAttachmentPoints(ListoldAPList, MapapMap) { ITopologyService topology = deviceManager.topology; List dupAPs = new ArrayList(); long timeThreshold = System.currentTimeMillis() - AttachmentPoint.INACTIVITY_INTERVAL; if (oldAPList == null || apMap == null) return dupAPs; for(AttachmentPoint ap: oldAPList) { long id = topology.getL2DomainId(ap.getSw()); AttachmentPoint trueAP = apMap.get(id); if (trueAP == null) continue; boolean c = (topology.isConsistent(trueAP.getSw(), trueAP.getPort(), ap.getSw(), ap.getPort())); boolean active = (ap.getActiveSince() > trueAP.getActiveSince()); boolean last = ap.getLastSeen() > timeThreshold; if (!c && active && last) { dupAPs.add(ap); } } return dupAPs; } /** * Update the known attachment points. This method is called whenever * topology changes. The method returns true if there's any change to * the list of attachment points -- which indicates a possible device * move. * @return */ protected boolean updateAttachmentPoint() { boolean moved = false; if (attachmentPoints == null || attachmentPoints.isEmpty()) return false; List apList = new ArrayList(); if (attachmentPoints != null) apList.addAll(attachmentPoints); Map newMap = getAPMap(apList); if (newMap == null || newMap.size() != apList.size()) { moved = true; } // Prepare the new attachment point list. if (moved) { List newAPList = new ArrayList(); if (newMap != null) newAPList.addAll(newMap.values()); this.attachmentPoints = newAPList; } // Set the oldAPs to null. this.oldAPs = null; return moved; } /** * Update the list of attachment points given that a new packet-in * was seen from (sw, port) at time (lastSeen). The return value is true * if there was any change to the list of attachment points for the device * -- which indicates a device move. * @param sw * @param port * @param lastSeen * @return */ protected boolean updateAttachmentPoint(long sw, short port, long lastSeen){ ITopologyService topology = deviceManager.topology; List oldAPList; List apList; boolean oldAPFlag = false; if (!deviceManager.isValidAttachmentPoint(sw, port)) return false; AttachmentPoint newAP = new AttachmentPoint(sw, port, lastSeen); //Copy the oldAP and ap list. apList = new ArrayList(); if (attachmentPoints != null) apList.addAll(attachmentPoints); oldAPList = new ArrayList(); if (oldAPs != null) oldAPList.addAll(oldAPs); // if the sw, port is in old AP, remove it from there // and update the lastSeen in that object. if (oldAPList.contains(newAP)) { int index = oldAPList.indexOf(newAP); newAP = oldAPList.remove(index); newAP.setLastSeen(lastSeen); this.oldAPs = oldAPList; oldAPFlag = true; } // newAP now contains the new attachment point. // Get the APMap is null or empty. Map apMap = getAPMap(apList); if (apMap == null || apMap.isEmpty()) { apList.add(newAP); attachmentPoints = apList; return true; } long id = topology.getL2DomainId(sw); AttachmentPoint oldAP = apMap.get(id); if (oldAP == null) // No attachment on this L2 domain. { apList = new ArrayList(); apList.addAll(apMap.values()); apList.add(newAP); this.attachmentPoints = apList; return true; // new AP found on an L2 island. } // There is already a known attachment point on the same L2 island. // we need to compare oldAP and newAP. if (oldAP.equals(newAP)) { // nothing to do here. just the last seen has to be changed. if (newAP.lastSeen > oldAP.lastSeen) { oldAP.setLastSeen(newAP.lastSeen); } this.attachmentPoints = new ArrayList(apMap.values()); return false; // nothing to do here. } int x = deviceManager.apComparator.compare(oldAP, newAP); if (x < 0) { // newAP replaces oldAP. apMap.put(id, newAP); this.attachmentPoints = new ArrayList(apMap.values()); oldAPList = new ArrayList(); if (oldAPs != null) oldAPList.addAll(oldAPs); oldAPList.add(oldAP); this.oldAPs = oldAPList; if (!topology.isInSameBroadcastDomain(oldAP.getSw(), oldAP.getPort(), newAP.getSw(), newAP.getPort())) return true; // attachment point changed. } else if (oldAPFlag) { // retain oldAP as is. Put the newAP in oldAPs for flagging // possible duplicates. oldAPList = new ArrayList(); if (oldAPs != null) oldAPList.addAll(oldAPs); // Add ot oldAPList only if it was picked up from the oldAPList oldAPList.add(newAP); this.oldAPs = oldAPList; } return false; } /** * Delete (sw,port) from the list of list of attachment points * and oldAPs. * @param sw * @param port * @return */ public boolean deleteAttachmentPoint(long sw, short port) { AttachmentPoint ap = new AttachmentPoint(sw, port, 0); if (this.oldAPs != null) { ArrayList apList = new ArrayList(); apList.addAll(this.oldAPs); int index = apList.indexOf(ap); if (index > 0) { apList.remove(index); this.oldAPs = apList; } } if (this.attachmentPoints != null) { ArrayList apList = new ArrayList(); apList.addAll(this.attachmentPoints); int index = apList.indexOf(ap); if (index > 0) { apList.remove(index); this.attachmentPoints = apList; return true; } } return false; } public boolean deleteAttachmentPoint(long sw) { boolean deletedFlag; ArrayList apList; ArrayList modifiedList; // Delete the APs on switch sw in oldAPs. deletedFlag = false; apList = new ArrayList(); if (this.oldAPs != null) apList.addAll(this.oldAPs); modifiedList = new ArrayList(); for(AttachmentPoint ap: apList) { if (ap.getSw() == sw) { deletedFlag = true; } else { modifiedList.add(ap); } } if (deletedFlag) { this.oldAPs = modifiedList; } // Delete the APs on switch sw in attachmentPoints. deletedFlag = false; apList = new ArrayList(); if (this.attachmentPoints != null) apList.addAll(this.attachmentPoints); modifiedList = new ArrayList(); for(AttachmentPoint ap: apList) { if (ap.getSw() == sw) { deletedFlag = true; } else { modifiedList.add(ap); } } if (deletedFlag) { this.attachmentPoints = modifiedList; return true; } return false; } @Override public SwitchPort[] getAttachmentPoints() { return getAttachmentPoints(false); } @Override public SwitchPort[] getAttachmentPoints(boolean includeError) { List sp = new ArrayList(); SwitchPort [] returnSwitchPorts = new SwitchPort[] {}; if (attachmentPoints == null) return returnSwitchPorts; if (attachmentPoints.isEmpty()) return returnSwitchPorts; // copy ap list. List apList; apList = new ArrayList(); if (attachmentPoints != null) apList.addAll(attachmentPoints); // get AP map. Map apMap = getAPMap(apList); if (apMap != null) { for(AttachmentPoint ap: apMap.values()) { SwitchPort swport = new SwitchPort(ap.getSw(), ap.getPort()); sp.add(swport); } } if (!includeError) return sp.toArray(new SwitchPort[sp.size()]); List oldAPList; oldAPList = new ArrayList(); if (oldAPs != null) oldAPList.addAll(oldAPs); if (removeExpiredAttachmentPoints(oldAPList)) this.oldAPs = oldAPList; List dupList; dupList = this.getDuplicateAttachmentPoints(oldAPList, apMap); if (dupList != null) { for(AttachmentPoint ap: dupList) { SwitchPort swport = new SwitchPort(ap.getSw(), ap.getPort(), ErrorStatus.DUPLICATE_DEVICE); sp.add(swport); } } return sp.toArray(new SwitchPort[sp.size()]); } // ******* // IDevice // ******* @Override public Long getDeviceKey() { return deviceKey; } @Override public long getMACAddress() { // we assume only one MAC per device for now. return entities[0].getMacAddress(); } @Override public String getMACAddressString() { return macAddressString; } @Override public Short[] getVlanId() { if (entities.length == 1) { if (entities[0].getVlan() != null) { return new Short[]{ entities[0].getVlan() }; } else { return new Short[] { Short.valueOf((short)-1) }; } } TreeSet vals = new TreeSet(); for (Entity e : entities) { if (e.getVlan() == null) vals.add((short)-1); else vals.add(e.getVlan()); } return vals.toArray(new Short[vals.size()]); } static final EnumSet ipv4Fields = EnumSet.of(DeviceField.IPV4); @Override public Integer[] getIPv4Addresses() { // XXX - TODO we can cache this result. Let's find out if this // is really a performance bottleneck first though. TreeSet vals = new TreeSet(); for (Entity e : entities) { if (e.getIpv4Address() == null) continue; // We have an IP address only if among the devices within the class // we have the most recent entity with that IP. boolean validIP = true; Iterator devices = deviceManager.queryClassByEntity(entityClass, ipv4Fields, e); while (devices.hasNext()) { Device d = devices.next(); if (deviceKey.equals(d.getDeviceKey())) continue; for (Entity se : d.entities) { if (se.getIpv4Address() != null && se.getIpv4Address().equals(e.getIpv4Address()) && se.getLastSeenTimestamp() != null && 0 < se.getLastSeenTimestamp(). compareTo(e.getLastSeenTimestamp())) { validIP = false; break; } } if (!validIP) break; } if (validIP) vals.add(e.getIpv4Address()); } return vals.toArray(new Integer[vals.size()]); } @Override public Short[] getSwitchPortVlanIds(SwitchPort swp) { TreeSet vals = new TreeSet(); for (Entity e : entities) { if (e.switchDPID == swp.getSwitchDPID() && e.switchPort == swp.getPort()) { if (e.getVlan() == null) vals.add(Ethernet.VLAN_UNTAGGED); else vals.add(e.getVlan()); } } return vals.toArray(new Short[vals.size()]); } @Override public Date getLastSeen() { Date d = null; for (int i = 0; i < entities.length; i++) { if (d == null || entities[i].getLastSeenTimestamp().compareTo(d) > 0) d = entities[i].getLastSeenTimestamp(); } return d; } // *************** // Getters/Setters // *************** @Override public IEntityClass getEntityClass() { return entityClass; } public Entity[] getEntities() { return entities; } // *************** // Utility Methods // *************** /** * Check whether the device contains the specified entity * @param entity the entity to search for * @return the index of the entity, or <0 if not found */ protected int entityIndex(Entity entity) { return Arrays.binarySearch(entities, entity); } // ****** // Object // ****** @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(entities); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Device other = (Device) obj; if (!deviceKey.equals(other.deviceKey)) return false; if (!Arrays.equals(entities, other.entities)) return false; return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Device [deviceKey="); builder.append(deviceKey); builder.append(", entityClass="); builder.append(entityClass.getName()); builder.append(", MAC="); builder.append(macAddressString); builder.append(", IPs=["); boolean isFirst = true; for (Integer ip: getIPv4Addresses()) { if (!isFirst) builder.append(", "); isFirst = false; builder.append(IPv4.fromIPv4Address(ip)); } builder.append("], APs="); builder.append(Arrays.toString(getAttachmentPoints(true))); builder.append("]"); return builder.toString(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java0000664000175000017500000000642312041336206034407 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.util.IterableIterator; /** * An index that maps key fields of an entity to device keys, with multiple * device keys allowed per entity */ public class DeviceMultiIndex extends DeviceIndex { /** * The index */ private ConcurrentHashMap> index; /** * @param keyFields */ public DeviceMultiIndex(EnumSet keyFields) { super(keyFields); index = new ConcurrentHashMap>(); } // *********** // DeviceIndex // *********** @Override public Iterator queryByEntity(Entity entity) { IndexedEntity ie = new IndexedEntity(keyFields, entity); Collection devices = index.get(ie); if (devices != null) return devices.iterator(); return Collections.emptySet().iterator(); } @Override public Iterator getAll() { Iterator> iter = index.values().iterator(); return new IterableIterator(iter); } @Override public boolean updateIndex(Device device, Long deviceKey) { for (Entity e : device.entities) { updateIndex(e, deviceKey); } return true; } @Override public void updateIndex(Entity entity, Long deviceKey) { Collection devices = null; IndexedEntity ie = new IndexedEntity(keyFields, entity); if (!ie.hasNonNullKeys()) return; devices = index.get(ie); if (devices == null) { Map chm = new ConcurrentHashMap(); devices = Collections.newSetFromMap(chm); Collection r = index.putIfAbsent(ie, devices); if (r != null) devices = r; } devices.add(deviceKey); } @Override public void removeEntity(Entity entity) { IndexedEntity ie = new IndexedEntity(keyFields, entity); index.remove(ie); } @Override public void removeEntity(Entity entity, Long deviceKey) { IndexedEntity ie = new IndexedEntity(keyFields, entity); Collection devices = index.get(ie); if (devices != null) devices.remove(deviceKey); } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java0000664000175000017500000002127712041336206032465 0ustar jamespagejamespage/** * Copyright 2011,2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Date; import net.floodlightcontroller.core.web.serializers.IPv4Serializer; import net.floodlightcontroller.core.web.serializers.MACSerializer; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.packet.IPv4; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; /** * An entity on the network is a visible trace of a device that corresponds * to a packet received from a particular interface on the edge of a network, * with a particular VLAN tag, and a particular MAC address, along with any * other packet characteristics we might want to consider as helpful for * disambiguating devices. * * Entities are the most basic element of devices; devices consist of one or * more entities. Entities are immutable once created, except for the last * seen timestamp. * * @author readams * */ public class Entity implements Comparable { /** * Timeout for computing {@link Entity#activeSince}. * @see {@link Entity#activeSince} */ protected static int ACTIVITY_TIMEOUT = 30000; /** * The MAC address associated with this entity */ protected long macAddress; /** * The IP address associated with this entity, or null if no IP learned * from the network observation associated with this entity */ protected Integer ipv4Address; /** * The VLAN tag on this entity, or null if untagged */ protected Short vlan; /** * The DPID of the switch for the ingress point for this entity, * or null if not present */ protected Long switchDPID; /** * The port number of the switch for the ingress point for this entity, * or null if not present */ protected Integer switchPort; /** * The last time we observed this entity on the network */ protected Date lastSeenTimestamp; /** * The time between {@link Entity#activeSince} and * {@link Entity#lastSeenTimestamp} is a period of activity for this * entity where it was observed repeatedly. If, when the entity is * observed, the is longer ago than the activity timeout, * {@link Entity#lastSeenTimestamp} and {@link Entity#activeSince} will * be set to the current time. */ protected Date activeSince; private int hashCode = 0; // ************ // Constructors // ************ /** * Create a new entity * * @param macAddress * @param vlan * @param ipv4Address * @param switchDPID * @param switchPort * @param lastSeenTimestamp */ public Entity(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort, Date lastSeenTimestamp) { this.macAddress = macAddress; this.ipv4Address = ipv4Address; this.vlan = vlan; this.switchDPID = switchDPID; this.switchPort = switchPort; this.lastSeenTimestamp = lastSeenTimestamp; this.activeSince = lastSeenTimestamp; } // *************** // Getters/Setters // *************** @JsonSerialize(using=MACSerializer.class) public long getMacAddress() { return macAddress; } @JsonSerialize(using=IPv4Serializer.class) public Integer getIpv4Address() { return ipv4Address; } public Short getVlan() { return vlan; } @JsonSerialize(using=DPIDSerializer.class) public Long getSwitchDPID() { return switchDPID; } public Integer getSwitchPort() { return switchPort; } public Date getLastSeenTimestamp() { return lastSeenTimestamp; } /** * Set the last seen timestamp and also update {@link Entity#activeSince} * if appropriate * @param lastSeenTimestamp the new last seen timestamp * @see {@link Entity#activeSince} */ public void setLastSeenTimestamp(Date lastSeenTimestamp) { if (activeSince == null || (activeSince.getTime() + ACTIVITY_TIMEOUT) < lastSeenTimestamp.getTime()) this.activeSince = lastSeenTimestamp; this.lastSeenTimestamp = lastSeenTimestamp; } public Date getActiveSince() { return activeSince; } public void setActiveSince(Date activeSince) { this.activeSince = activeSince; } @Override public int hashCode() { if (hashCode != 0) return hashCode; final int prime = 31; hashCode = 1; hashCode = prime * hashCode + ((ipv4Address == null) ? 0 : ipv4Address.hashCode()); hashCode = prime * hashCode + (int) (macAddress ^ (macAddress >>> 32)); hashCode = prime * hashCode + ((switchDPID == null) ? 0 : switchDPID.hashCode()); hashCode = prime * hashCode + ((switchPort == null) ? 0 : switchPort.hashCode()); hashCode = prime * hashCode + ((vlan == null) ? 0 : vlan.hashCode()); return hashCode; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Entity other = (Entity) obj; if (hashCode() != other.hashCode()) return false; if (ipv4Address == null) { if (other.ipv4Address != null) return false; } else if (!ipv4Address.equals(other.ipv4Address)) return false; if (macAddress != other.macAddress) return false; if (switchDPID == null) { if (other.switchDPID != null) return false; } else if (!switchDPID.equals(other.switchDPID)) return false; if (switchPort == null) { if (other.switchPort != null) return false; } else if (!switchPort.equals(other.switchPort)) return false; if (vlan == null) { if (other.vlan != null) return false; } else if (!vlan.equals(other.vlan)) return false; return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Entity [macAddress="); builder.append(HexString.toHexString(macAddress, 6)); builder.append(", ipv4Address="); builder.append(IPv4.fromIPv4Address(ipv4Address==null ? 0 : ipv4Address.intValue())); builder.append(", vlan="); builder.append(vlan); builder.append(", switchDPID="); builder.append(switchDPID); builder.append(", switchPort="); builder.append(switchPort); builder.append(", lastSeenTimestamp="); builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime()); builder.append(", activeSince="); builder.append(activeSince == null? "null" : activeSince.getTime()); builder.append("]"); return builder.toString(); } @Override public int compareTo(Entity o) { if (macAddress < o.macAddress) return -1; if (macAddress > o.macAddress) return 1; int r; if (switchDPID == null) r = o.switchDPID == null ? 0 : -1; else if (o.switchDPID == null) r = 1; else r = switchDPID.compareTo(o.switchDPID); if (r != 0) return r; if (switchPort == null) r = o.switchPort == null ? 0 : -1; else if (o.switchPort == null) r = 1; else r = switchPort.compareTo(o.switchPort); if (r != 0) return r; if (ipv4Address == null) r = o.ipv4Address == null ? 0 : -1; else if (o.ipv4Address == null) r = 1; else r = ipv4Address.compareTo(o.ipv4Address); if (r != 0) return r; if (vlan == null) r = o.vlan == null ? 0 : -1; else if (o.vlan == null) r = 1; else r = vlan.compareTo(o.vlan); if (r != 0) return r; return 0; } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.javafloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.j0000664000175000017500000000336512041336206034576 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.Iterator; /** * An iterator for handling device index queries */ public class DeviceIndexInterator implements Iterator { private DeviceManagerImpl deviceManager; private Iterator subIterator; /** * Construct a new device index iterator referring to a device manager * instance and an iterator over device keys * * @param deviceManager the device manager * @param subIterator an iterator over device keys */ public DeviceIndexInterator(DeviceManagerImpl deviceManager, Iterator subIterator) { super(); this.deviceManager = deviceManager; this.subIterator = subIterator; } @Override public boolean hasNext() { return subIterator.hasNext(); } @Override public Device next() { Long next = subIterator.next(); return deviceManager.deviceMap.get(next); } @Override public void remove() { subIterator.remove(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java0000664000175000017500000001250512041336206033760 0ustar jamespagejamespagepackage net.floodlightcontroller.devicemanager.internal; import java.util.EnumSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; /** * This is a thin wrapper around {@link Entity} that allows overriding * the behavior of {@link Object#hashCode()} and {@link Object#equals(Object)} * so that the keying behavior in a hash map can be changed dynamically * @author readams */ public class IndexedEntity { protected EnumSet keyFields; protected Entity entity; private int hashCode = 0; protected static Logger logger = LoggerFactory.getLogger(IndexedEntity.class); /** * Create a new {@link IndexedEntity} for the given {@link Entity} using * the provided key fields. * @param keyFields The key fields that will be used for computing * {@link IndexedEntity#hashCode()} and {@link IndexedEntity#equals(Object)} * @param entity the entity to wrap */ public IndexedEntity(EnumSet keyFields, Entity entity) { super(); this.keyFields = keyFields; this.entity = entity; } /** * Check whether this entity has non-null values in any of its key fields * @return true if any key fields have a non-null value */ public boolean hasNonNullKeys() { for (DeviceField f : keyFields) { switch (f) { case MAC: return true; case IPV4: if (entity.ipv4Address != null) return true; break; case SWITCH: if (entity.switchDPID != null) return true; break; case PORT: if (entity.switchPort != null) return true; break; case VLAN: if (entity.vlan != null) return true; break; } } return false; } @Override public int hashCode() { if (hashCode != 0) { return hashCode; } final int prime = 31; hashCode = 1; for (DeviceField f : keyFields) { switch (f) { case MAC: hashCode = prime * hashCode + (int) (entity.macAddress ^ (entity.macAddress >>> 32)); break; case IPV4: hashCode = prime * hashCode + ((entity.ipv4Address == null) ? 0 : entity.ipv4Address.hashCode()); break; case SWITCH: hashCode = prime * hashCode + ((entity.switchDPID == null) ? 0 : entity.switchDPID.hashCode()); break; case PORT: hashCode = prime * hashCode + ((entity.switchPort == null) ? 0 : entity.switchPort.hashCode()); break; case VLAN: hashCode = prime * hashCode + ((entity.vlan == null) ? 0 : entity.vlan.hashCode()); break; } } return hashCode; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; IndexedEntity other = (IndexedEntity) obj; if (!keyFields.equals(other.keyFields)) return false; for (IDeviceService.DeviceField f : keyFields) { switch (f) { case MAC: if (entity.macAddress != other.entity.macAddress) return false; break; case IPV4: if (entity.ipv4Address == null) { if (other.entity.ipv4Address != null) return false; } else if (!entity.ipv4Address. equals(other.entity.ipv4Address)) return false; break; case SWITCH: if (entity.switchDPID == null) { if (other.entity.switchDPID != null) return false; } else if (!entity.switchDPID. equals(other.entity.switchDPID)) return false; break; case PORT: if (entity.switchPort == null) { if (other.entity.switchPort != null) return false; } else if (!entity.switchPort. equals(other.entity.switchPort)) return false; break; case VLAN: if (entity.vlan == null) { if (other.entity.vlan != null) return false; } else if (!entity.vlan. equals(other.entity.vlan)) return false; break; } } return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java0000775000175000017500000002037312041336206032225 0ustar jamespagejamespage/** * Copyright 2011,2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import net.floodlightcontroller.core.FloodlightContextStore; import net.floodlightcontroller.core.module.IFloodlightService; /** * Device manager allows interacting with devices on the network. Note * that under normal circumstances, {@link Device} objects should be retrieved * from the {@link FloodlightContext} rather than from {@link IDeviceManager}. */ public interface IDeviceService extends IFloodlightService { /** * Fields used in devices for indexes and querying * @see IDeviceService#addIndex */ enum DeviceField { MAC, IPV4, VLAN, SWITCH, PORT } /** * The source device for the current packet-in, if applicable. */ public static final String CONTEXT_SRC_DEVICE = "net.floodlightcontroller.devicemanager.srcDevice"; /** * The destination device for the current packet-in, if applicable. */ public static final String CONTEXT_DST_DEVICE = "net.floodlightcontroller.devicemanager.dstDevice"; /** * A FloodlightContextStore object that can be used to interact with the * FloodlightContext information created by BVS manager. */ public static final FloodlightContextStore fcStore = new FloodlightContextStore(); /** * Get the device with the given device key. * * @param deviceKey the key to search for * @return the device associated with the key, or null if no such device * @see IDevice#getDeviceKey() */ public IDevice getDevice(Long deviceKey); /** * Search for a device exactly matching the provided device fields. This * is the same lookup process that is used for packet_in processing and * device learning. Thus, findDevice() can be used to match flow entries * from switches to devices. * Only the key fields as defined by the {@link IEntityClassifierService} will * be important in this search. All key fields MUST be supplied. * *{@link queryDevices()} might be more appropriate! * * @param macAddress The MAC address * @param vlan the VLAN. Null means no VLAN and is valid even if VLAN is a * key field. * @param ipv4Address the ipv4 address * @param switchDPID the switch DPID * @param switchPort the switch port * @return an {@link IDevice} or null if no device is found. * @see IDeviceManager#setEntityClassifier(IEntityClassifierService) * @throws IllegalArgumentException if not all key fields of the * current {@link IEntityClassifierService} are specified. */ public IDevice findDevice(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) throws IllegalArgumentException; /** * Get a destination device using entity fields that corresponds with * the given source device. The source device is important since * there could be ambiguity in the destination device without the * attachment point information. * * @param source the source device. The returned destination will be * in the same entity class as the source. * @param macAddress The MAC address for the destination * @param vlan the VLAN if available * @param ipv4Address The IP address if available. * @return an {@link IDevice} or null if no device is found. * @see IDeviceService#findDevice(long, Short, Integer, Long, * Integer) * @throws IllegalArgumentException if not all key fields of the * source's {@link IEntityClass} are specified. */ public IDevice findDestDevice(IDevice source, long macAddress, Short vlan, Integer ipv4Address) throws IllegalArgumentException; /** * Get an unmodifiable collection view over all devices currently known. * @return the collection of all devices */ public Collection getAllDevices(); /** * Create an index over a set of fields. This allows efficient lookup * of devices when querying using the indexed set of specified fields. * The index must be registered before any device learning takes place, * or it may be incomplete. It's OK if this is called multiple times with * the same fields; only one index will be created for each unique set of * fields. * * @param perClass set to true if the index should be maintained for each * entity class separately. * @param keyFields the set of fields on which to index */ public void addIndex(boolean perClass, EnumSet keyFields); /** * Find devices that match the provided query. Any fields that are * null will not be included in the query. If there is an index for * the query, then it will be performed efficiently using the index. * Otherwise, there will be a full scan of the device list. * * @param macAddress The MAC address * @param vlan the VLAN * @param ipv4Address the ipv4 address * @param switchDPID the switch DPID * @param switchPort the switch port * @return an iterator over a set of devices matching the query * @see IDeviceService#queryClassDevices(IEntityClass, Long, * Short, Integer, Long, Integer) */ public Iterator queryDevices(Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort); /** * Find devices that match the provided query. Only the index for * the class of the specified reference device will be searched. * Any fields that are null will not be included in the query. If * there is an index for the query, then it will be performed * efficiently using the index. Otherwise, there will be a full scan * of the device list. * * @param reference The reference device to refer to when finding * entity classes. * @param macAddress The MAC address * @param vlan the VLAN * @param ipv4Address the ipv4 address * @param switchDPID the switch DPID * @param switchPort the switch port * @return an iterator over a set of devices matching the query * @see IDeviceService#queryClassDevices(Long, * Short, Integer, Long, Integer) */ public Iterator queryClassDevices(IDevice reference, Long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort); /** * Adds a listener to listen for IDeviceManagerServices notifications * * @param listener The listener that wants the notifications */ public void addListener(IDeviceListener listener); /** * Specify points in the network where attachment points are not to * be learned. * @param sw * @param port */ public void addSuppressAPs(long swId, short port); public void removeSuppressAPs(long swId, short port); } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IEntityClass.java0000664000175000017500000000437312041336206031746 0ustar jamespagejamespage/** * Copyright 2011,2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import java.util.EnumSet; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.internal.Device; /** * Entities within an entity class are grouped into {@link Device} objects * based on the {@link IEntityClass}, and the key fields specified by the entity * class. A set of entities are considered to be the same device if and only * if they belong to the same entity class and they match on all key fields * for that entity class. A field is effectively wildcarded by not including * it in the list of key fields returned by {@link IEntityClassifierService} and/or * {@link IEntityClass}. * * Note that if you're not using static objects, you'll need to override * {@link Object#equals(Object)} and {@link Object#hashCode()}. * * @author readams * */ public interface IEntityClass { /** * Return the set of key fields for this entity class. Entities * belonging to this class that differ in fields not included in * this collection will be considered the same device. The key * fields for an entity class must not change unless associated * with a flush of that entity class. * * @return a set containing the fields that should not * be wildcarded. May be null to indicate that all fields are key fields. */ EnumSet getKeyFields(); /** * Returns a user-friendly, unique name for this EntityClass * @return the name of the entity class */ String getName(); } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java0000664000175000017500000000377612041336206032417 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; /** * Implementors of this interface can receive updates from DeviceManager about * the state of devices under its control. * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IDeviceListener { /** * Called when a new Device is found * @param device the device that changed */ public void deviceAdded(IDevice device); /** * Called when a Device is removed, this typically occurs when the port the * Device is attached to goes down, or the switch it is attached to is * removed. * @param device the device that changed */ public void deviceRemoved(IDevice device); /** * Called when a Device has moved to a new location on the network. Note * that either the switch or the port or both has changed. * * @param device the device that changed */ public void deviceMoved(IDevice device); /** * Called when a network address has been added or remove from a device * * @param device the device that changed */ public void deviceIPV4AddrChanged(IDevice device); /** * Called when a VLAN tag for the device has been added or removed * @param device the device that changed */ public void deviceVlanChanged(IDevice device); } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/0000775000175000017500000000000012041336206027276 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java0000664000175000017500000001722212041336206034540 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.web; import java.util.Iterator; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.internal.Device; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.util.FilterIterator; import org.openflow.util.HexString; import org.restlet.data.Form; import org.restlet.data.Status; import org.restlet.resource.ServerResource; /** * Resource for querying and displaying devices that exist in the system */ public abstract class AbstractDeviceResource extends ServerResource { public static final String MAC_ERROR = "Invalid MAC address: must be a 48-bit quantity, " + "expressed in hex as AA:BB:CC:DD:EE:FF"; public static final String VLAN_ERROR = "Invalid VLAN: must be an integer in the range 0-4095"; public static final String IPV4_ERROR = "Invalid IPv4 address: must be in dotted decimal format, " + "234.0.59.1"; public static final String DPID_ERROR = "Invalid Switch DPID: must be a 64-bit quantity, expressed in " + "hex as AA:BB:CC:DD:EE:FF:00:11"; public static final String PORT_ERROR = "Invalid Port: must be a positive integer"; public Iterator getDevices() { IDeviceService deviceManager = (IDeviceService)getContext().getAttributes(). get(IDeviceService.class.getCanonicalName()); Long macAddress = null; Short vlan = null; Integer ipv4Address = null; Long switchDPID = null; Integer switchPort = null; Form form = getQuery(); String macAddrStr = form.getFirstValue("mac", true); String vlanStr = form.getFirstValue("vlan", true); String ipv4Str = form.getFirstValue("ipv4", true); String dpid = form.getFirstValue("dpid", true); String port = form.getFirstValue("port", true); if (macAddrStr != null) { try { macAddress = HexString.toLong(macAddrStr); } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, MAC_ERROR); return null; } } if (vlanStr != null) { try { vlan = Short.parseShort(vlanStr); if (vlan > 4095 || vlan < 0) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR); return null; } } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR); return null; } } if (ipv4Str != null) { try { ipv4Address = IPv4.toIPv4Address(ipv4Str); } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, IPV4_ERROR); return null; } } if (dpid != null) { try { switchDPID = HexString.toLong(dpid); } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR); return null; } } if (port != null) { try { switchPort = Integer.parseInt(port); if (switchPort < 0) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR); return null; } } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR); return null; } } @SuppressWarnings("unchecked") Iterator diter = (Iterator) deviceManager.queryDevices(macAddress, vlan, ipv4Address, switchDPID, switchPort); final String macStartsWith = form.getFirstValue("mac__startswith", true); final String vlanStartsWith = form.getFirstValue("vlan__startswith", true); final String ipv4StartsWith = form.getFirstValue("ipv4__startswith", true); final String dpidStartsWith = form.getFirstValue("dpid__startswith", true); final String portStartsWith = form.getFirstValue("port__startswith", true); return new FilterIterator(diter) { @Override protected boolean matches(Device value) { if (macStartsWith != null) { if (!value.getMACAddressString().startsWith(macStartsWith)) return false; } if (vlanStartsWith != null) { boolean match = false; for (Short v : value.getVlanId()) { if (v != null && v.toString().startsWith(vlanStartsWith)) { match = true; break; } } if (!match) return false; } if (ipv4StartsWith != null) { boolean match = false; for (Integer v : value.getIPv4Addresses()) { String str = IPv4.fromIPv4Address(v); if (v != null && str.startsWith(ipv4StartsWith)) { match = true; break; } } if (!match) return false; } if (dpidStartsWith != null) { boolean match = false; for (SwitchPort v : value.getAttachmentPoints(true)) { String str = HexString.toHexString(v.getSwitchDPID(), 8); if (v != null && str.startsWith(dpidStartsWith)) { match = true; break; } } if (!match) return false; } if (portStartsWith != null) { boolean match = false; for (SwitchPort v : value.getAttachmentPoints(true)) { String str = Integer.toString(v.getPort()); if (v != null && str.startsWith(portStartsWith)) { match = true; break; } } if (!match) return false; } return true; } }; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceResource.java0000664000175000017500000000214112041336206033046 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.web; import java.util.Iterator; import net.floodlightcontroller.devicemanager.IDevice; import org.restlet.resource.Get; /** * Resource for querying and displaying devices that exist in the system */ public class DeviceResource extends AbstractDeviceResource { @Get("json") public Iterator getDevices() { return super.getDevices(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceEntityResource.java0000664000175000017500000000340512041336206034247 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.web; import java.util.Iterator; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.internal.Device; import net.floodlightcontroller.devicemanager.internal.Entity; import org.restlet.resource.Get; /** * Resource for querying and displaying internal debug information on * network entities associated with devices */ public class DeviceEntityResource extends AbstractDeviceResource { @Get("json") public Iterator getDeviceEntities() { final Iterator devices = super.getDevices(); return new Iterator() { @Override public boolean hasNext() { return devices.hasNext(); } @Override public Entity[] next() { Device d = (Device)devices.next(); return d.getEntities(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java0000664000175000017500000000246712041336206033047 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.web; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import net.floodlightcontroller.restserver.RestletRoutable; /** * Routable for device rest api */ public class DeviceRoutable implements RestletRoutable { @Override public String basePath() { return "/wm/device"; } @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/", DeviceResource.class); router.attach("/debug", DeviceEntityResource.class); return router; } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java0000664000175000017500000000463112041336206033376 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.web; import java.io.IOException; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.internal.Device; import net.floodlightcontroller.packet.IPv4; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.util.HexString; /** * Serialize a device object */ public class DeviceSerializer extends JsonSerializer { @Override public void serialize(Device device, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); jGen.writeStringField("entityClass", device.getEntityClass().getName()); jGen.writeArrayFieldStart("mac"); jGen.writeString(HexString.toHexString(device.getMACAddress(), 6)); jGen.writeEndArray(); jGen.writeArrayFieldStart("ipv4"); for (Integer ip : device.getIPv4Addresses()) jGen.writeString(IPv4.fromIPv4Address(ip)); jGen.writeEndArray(); jGen.writeArrayFieldStart("vlan"); for (Short vlan : device.getVlanId()) if (vlan >= 0) jGen.writeNumber(vlan); jGen.writeEndArray(); jGen.writeArrayFieldStart("attachmentPoint"); for (SwitchPort ap : device.getAttachmentPoints(true)) { serializer.defaultSerializeValue(ap, jGen); } jGen.writeEndArray(); jGen.writeNumberField("lastSeen", device.getLastSeen().getTime()); jGen.writeEndObject(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java0000664000175000017500000000625312041336206030702 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import java.util.Date; /** * Represents an independent device on the network. A device consists of a * set of entities, and all the information known about a given device comes * only from merging all associated entities for that device. * @author readams */ public interface IDevice { /** * Get the primary key for this device. * @return the primary key */ public Long getDeviceKey(); /** * Get the MAC address of the device as a Long value. * @return the MAC address for the device */ public long getMACAddress(); /** * Get the MAC address of the device as a String value. * @return the MAC address for the device */ public String getMACAddressString(); /** * Get all unique VLAN IDs for the device. If the device has untagged * entities, then the value -1 will be returned. * @return an array containing all unique VLAN IDs for the device. */ public Short[] getVlanId(); /** * Get all unique IPv4 addresses associated with the device. * @return an array containing the unique IPv4 addresses for the device. */ public Integer[] getIPv4Addresses(); /** * Get all unique attachment points associated with the device. This will * not include any blocked attachment points. * @return an array containing all unique attachment points for the device */ public SwitchPort[] getAttachmentPoints(); /** * Get all unique attachment points associated with the device. * @param includeError whether to include blocked attachment points. * Blocked attachment points should not be used for forwarding, but * could be useful to show to a user * @return an array containing all unique attachment points for the device */ public SwitchPort[] getAttachmentPoints(boolean includeError); /** * Returns all unique VLAN IDs for the device that were observed on * the given switch port * @param swp the switch port to query * @return an array containing the unique VLAN IDs */ public Short[] getSwitchPortVlanIds(SwitchPort swp); /** * Get the most recent timestamp for this device * @return the last seen timestamp */ public Date getLastSeen(); /** * Get the entity class for the device. * @return the entity class * @see IEntityClassifierService */ public IEntityClass getEntityClass(); } floodlight-0.90/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassListener.java0000664000175000017500000000224412041336206033447 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager; import java.util.Set; /** * Implementors of this interface can receive updates from DeviceManager about * the changes entity Classes. * * @author Ananth Suryanarayana (Ananth.Suryanarayana@bigswitch.com) */ public interface IEntityClassListener { /** * Process entity classes change event. * @param entityClassNames Set of entity classes changed */ public void entityClassChanged(Set entityClassNames); } floodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/0000775000175000017500000000000012041336206027170 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java0000664000175000017500000010105412041336206033445 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.packet.IPv4; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.MappingJsonFactory; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionDataLayerDestination; import org.openflow.protocol.action.OFActionDataLayerSource; import org.openflow.protocol.action.OFActionEnqueue; import org.openflow.protocol.action.OFActionNetworkLayerDestination; import org.openflow.protocol.action.OFActionNetworkLayerSource; import org.openflow.protocol.action.OFActionNetworkTypeOfService; import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.action.OFActionStripVirtualLan; import org.openflow.protocol.action.OFActionTransportLayerDestination; import org.openflow.protocol.action.OFActionTransportLayerSource; import org.openflow.protocol.action.OFActionVirtualLanIdentifier; import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; import org.openflow.util.HexString; /** * Represents static flow entries to be maintained by the controller on the * switches. */ @LogMessageCategory("Static Flow Pusher") public class StaticFlowEntries { protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class); private static class SubActionStruct { OFAction action; int len; } private static byte[] zeroMac = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; /** * This function generates a random hash for the bottom half of the cookie * * @param fm * @param userCookie * @param name * @return A cookie that encodes the application ID and a hash */ public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) { // flow-specific hash is next 20 bits LOOK! who knows if this int prime = 211; int flowHash = 2311; for (int i=0; i < name.length(); i++) flowHash = flowHash * prime + (int)name.charAt(i); return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash); } /** * Sets defaults for an OFFlowMod * @param fm The OFFlowMod to set defaults for * @param entryName The name of the entry. Used to compute the cookie. */ public static void initDefaultFlowMod(OFFlowMod fm, String entryName) { fm.setIdleTimeout((short) 0); // infinite fm.setHardTimeout((short) 0); // infinite fm.setBufferId(OFPacketOut.BUFFER_ID_NONE); fm.setCommand((short) 0); fm.setFlags((short) 0); fm.setOutPort(OFPort.OFPP_NONE.getValue()); fm.setCookie(computeEntryCookie(fm, 0, entryName)); fm.setPriority(Short.MAX_VALUE); } /** * Gets the entry name of a flow mod * @param fmJson The OFFlowMod in a JSON representation * @return The name of the OFFlowMod, null if not found * @throws IOException If there was an error parsing the JSON */ public static String getEntryNameFromJson(String fmJson) throws IOException{ MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(fmJson); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; if (n == "name") return jp.getText(); } return null; } /** * Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format. * @param fm The FlowMod to parse * @param sw The switch the FlowMod is going to be installed on * @param name The name of this static flow entry * @return A Map representation of the storage entry */ public static Map flowModToStorageEntry(OFFlowMod fm, String sw, String name) { Map entry = new HashMap(); OFMatch match = fm.getMatch(); entry.put(StaticFlowEntryPusher.COLUMN_NAME, name); entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw); entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true)); entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Short.toString(fm.getPriority())); entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards())); if ((fm.getActions() != null) && (fm.getActions().size() > 0)) entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions())); if (match.getInputPort() != 0) entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Short.toString(match.getInputPort())); if (!Arrays.equals(match.getDataLayerSource(), zeroMac)) entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, HexString.toHexString(match.getDataLayerSource())); if (!Arrays.equals(match.getDataLayerDestination(), zeroMac)) entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, HexString.toHexString(match.getDataLayerDestination())); if (match.getDataLayerVirtualLan() != -1) entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, Short.toString(match.getDataLayerVirtualLan())); if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Short.toString(match.getDataLayerVirtualLanPriorityCodePoint())); if (match.getDataLayerType() != 0) entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, Short.toString(match.getDataLayerType())); if (match.getNetworkTypeOfService() != 0) entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Short.toString(match.getNetworkTypeOfService())); if (match.getNetworkProtocol() != 0) entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.getNetworkProtocol())); if (match.getNetworkSource() != 0) entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, IPv4.fromIPv4Address(match.getNetworkSource())); if (match.getNetworkDestination() != 0) entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, IPv4.fromIPv4Address(match.getNetworkDestination())); if (match.getTransportSource() != 0) entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, Short.toString(match.getTransportSource())); if (match.getTransportDestination() != 0) entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, Short.toString(match.getTransportDestination())); return entry; } /** * Returns a String representation of all the openflow actions. * @param fmActions A list of OFActions to encode into one string * @return A string of the actions encoded for our database */ @LogMessageDoc(level="ERROR", message="Could not decode action {action}", explanation="A static flow entry contained an invalid action", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) private static String flowModActionsToString(List fmActions) { StringBuilder sb = new StringBuilder(); for (OFAction a : fmActions) { if (sb.length() > 0) { sb.append(','); } switch(a.getType()) { case OUTPUT: sb.append("output=" + Short.toString(((OFActionOutput)a).getPort())); break; case OPAQUE_ENQUEUE: int queue = ((OFActionEnqueue)a).getQueueId(); short port = ((OFActionEnqueue)a).getPort(); sb.append("enqueue=" + Short.toString(port) + ":0x" + String.format("%02x", queue)); break; case STRIP_VLAN: sb.append("strip-vlan"); break; case SET_VLAN_ID: sb.append("set-vlan-id=" + Short.toString(((OFActionVirtualLanIdentifier)a).getVirtualLanIdentifier())); break; case SET_VLAN_PCP: sb.append("set-vlan-priority=" + Byte.toString(((OFActionVirtualLanPriorityCodePoint)a).getVirtualLanPriorityCodePoint())); break; case SET_DL_SRC: sb.append("set-src-mac=" + HexString.toHexString(((OFActionDataLayerSource)a).getDataLayerAddress())); break; case SET_DL_DST: sb.append("set-dst-mac=" + HexString.toHexString(((OFActionDataLayerDestination)a).getDataLayerAddress())); break; case SET_NW_TOS: sb.append("set-tos-bits=" + Byte.toString(((OFActionNetworkTypeOfService)a).getNetworkTypeOfService())); break; case SET_NW_SRC: sb.append("set-src-ip=" + IPv4.fromIPv4Address(((OFActionNetworkLayerSource)a).getNetworkAddress())); break; case SET_NW_DST: sb.append("set-dst-ip=" + IPv4.fromIPv4Address(((OFActionNetworkLayerDestination)a).getNetworkAddress())); break; case SET_TP_SRC: sb.append("set-src-port=" + Short.toString(((OFActionTransportLayerSource)a).getTransportPort())); break; case SET_TP_DST: sb.append("set-dst-port=" + Short.toString(((OFActionTransportLayerDestination)a).getTransportPort())); break; default: log.error("Could not decode action: {}", a); break; } } return sb.toString(); } /** * Turns a JSON formatted Static Flow Pusher string into a storage entry * Expects a string in JSON along the lines of: * { * "switch": "AA:BB:CC:DD:EE:FF:00:11", * "name": "flow-mod-1", * "cookie": "0", * "priority": "32768", * "ingress-port": "1", * "actions": "output=2", * } * @param fmJson The JSON formatted static flow pusher entry * @return The map of the storage entry * @throws IOException If there was an error parsing the JSON */ public static Map jsonToStorageEntry(String fmJson) throws IOException { Map entry = new HashMap(); MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(fmJson); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; if (n == "name") entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText()); else if (n == "switch") entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText()); else if (n == "actions") entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText()); else if (n == "priority") entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText()); else if (n == "active") entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText()); else if (n == "wildcards") entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, jp.getText()); else if (n == "ingress-port") entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText()); else if (n == "src-mac") entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText()); else if (n == "dst-mac") entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText()); else if (n == "vlan-id") entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText()); else if (n == "vlan-priority") entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText()); else if (n == "ether-type") entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText()); else if (n == "tos-bits") entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText()); else if (n == "protocol") entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText()); else if (n == "src-ip") entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText()); else if (n == "dst-ip") entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText()); else if (n == "src-port") entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText()); else if (n == "dst-port") entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText()); } return entry; } /** * Parses OFFlowMod actions from strings. * @param flowMod The OFFlowMod to set the actions for * @param actionstr The string containing all the actions * @param log A logger to log for errors. */ @LogMessageDoc(level="ERROR", message="Unexpected action '{action}', '{subaction}'", explanation="A static flow entry contained an invalid action", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) { List actions = new LinkedList(); int actionsLength = 0; if (actionstr != null) { actionstr = actionstr.toLowerCase(); for (String subaction : actionstr.split(",")) { String action = subaction.split("[=:]")[0]; SubActionStruct subaction_struct = null; if (action.equals("output")) { subaction_struct = StaticFlowEntries.decode_output(subaction, log); } else if (action.equals("enqueue")) { subaction_struct = decode_enqueue(subaction, log); } else if (action.equals("strip-vlan")) { subaction_struct = decode_strip_vlan(subaction, log); } else if (action.equals("set-vlan-id")) { subaction_struct = decode_set_vlan_id(subaction, log); } else if (action.equals("set-vlan-priority")) { subaction_struct = decode_set_vlan_priority(subaction, log); } else if (action.equals("set-src-mac")) { subaction_struct = decode_set_src_mac(subaction, log); } else if (action.equals("set-dst-mac")) { subaction_struct = decode_set_dst_mac(subaction, log); } else if (action.equals("set-tos-bits")) { subaction_struct = decode_set_tos_bits(subaction, log); } else if (action.equals("set-src-ip")) { subaction_struct = decode_set_src_ip(subaction, log); } else if (action.equals("set-dst-ip")) { subaction_struct = decode_set_dst_ip(subaction, log); } else if (action.equals("set-src-port")) { subaction_struct = decode_set_src_port(subaction, log); } else if (action.equals("set-dst-port")) { subaction_struct = decode_set_dst_port(subaction, log); } else { log.error("Unexpected action '{}', '{}'", action, subaction); } if (subaction_struct != null) { actions.add(subaction_struct.action); actionsLength += subaction_struct.len; } } } log.debug("action {}", actions); flowMod.setActions(actions); flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength); } @LogMessageDoc(level="ERROR", message="Invalid subaction: '{subaction}'", explanation="A static flow entry contained an invalid subaction", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) private static SubActionStruct decode_output(String subaction, Logger log) { SubActionStruct sa = null; Matcher n; n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction); if (n.matches()) { OFActionOutput action = new OFActionOutput(); action.setMaxLength((short) Short.MAX_VALUE); short port = OFPort.OFPP_NONE.getValue(); if (n.group(1) != null) { try { port = get_short(n.group(1)); } catch (NumberFormatException e) { log.debug("Invalid port in: '{}' (error ignored)", subaction); return null; } } else if (n.group(2) != null) port = OFPort.OFPP_ALL.getValue(); else if (n.group(3) != null) port = OFPort.OFPP_CONTROLLER.getValue(); else if (n.group(4) != null) port = OFPort.OFPP_LOCAL.getValue(); else if (n.group(5) != null) port = OFPort.OFPP_IN_PORT.getValue(); else if (n.group(6) != null) port = OFPort.OFPP_NORMAL.getValue(); else if (n.group(7) != null) port = OFPort.OFPP_FLOOD.getValue(); action.setPort(port); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionOutput.MINIMUM_LENGTH; } else { log.error("Invalid subaction: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_enqueue(String subaction, Logger log) { SubActionStruct sa = null; Matcher n; n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction); if (n.matches()) { short portnum = 0; if (n.group(1) != null) { try { portnum = get_short(n.group(1)); } catch (NumberFormatException e) { log.debug("Invalid port-num in: '{}' (error ignored)", subaction); return null; } } int queueid = 0; if (n.group(2) != null) { try { queueid = get_int(n.group(2)); } catch (NumberFormatException e) { log.debug("Invalid queue-id in: '{}' (error ignored)", subaction); return null; } } OFActionEnqueue action = new OFActionEnqueue(); action.setPort(portnum); action.setQueueId(queueid); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionEnqueue.MINIMUM_LENGTH; } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_strip_vlan(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("strip-vlan").matcher(subaction); if (n.matches()) { OFActionStripVirtualLan action = new OFActionStripVirtualLan(); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH; } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction); if (n.matches()) { if (n.group(1) != null) { try { short vlanid = get_short(n.group(1)); OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier(); action.setVirtualLanIdentifier(vlanid); log.debug(" action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH; } catch (NumberFormatException e) { log.debug("Invalid VLAN in: {} (error ignored)", subaction); return null; } } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); if (n.matches()) { if (n.group(1) != null) { try { byte prior = get_byte(n.group(1)); OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint(); action.setVirtualLanPriorityCodePoint(prior); log.debug(" action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH; } catch (NumberFormatException e) { log.debug("Invalid VLAN priority in: {} (error ignored)", subaction); return null; } } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_src_mac(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); if (n.matches()) { byte[] macaddr = get_mac_addr(n, subaction, log); if (macaddr != null) { OFActionDataLayerSource action = new OFActionDataLayerSource(); action.setDataLayerAddress(macaddr); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionDataLayerSource.MINIMUM_LENGTH; } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); if (n.matches()) { byte[] macaddr = get_mac_addr(n, subaction, log); if (macaddr != null) { OFActionDataLayerDestination action = new OFActionDataLayerDestination(); action.setDataLayerAddress(macaddr); log.debug(" action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH; } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); if (n.matches()) { if (n.group(1) != null) { try { byte tosbits = get_byte(n.group(1)); OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService(); action.setNetworkTypeOfService(tosbits); log.debug(" action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH; } catch (NumberFormatException e) { log.debug("Invalid dst-port in: {} (error ignored)", subaction); return null; } } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_src_ip(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); if (n.matches()) { int ipaddr = get_ip_addr(n, subaction, log); OFActionNetworkLayerSource action = new OFActionNetworkLayerSource(); action.setNetworkAddress(ipaddr); log.debug(" action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH; } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); if (n.matches()) { int ipaddr = get_ip_addr(n, subaction, log); OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination(); action.setNetworkAddress(ipaddr); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH; } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_src_port(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); if (n.matches()) { if (n.group(1) != null) { try { short portnum = get_short(n.group(1)); OFActionTransportLayerSource action = new OFActionTransportLayerSource(); action.setTransportPort(portnum); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;; } catch (NumberFormatException e) { log.debug("Invalid src-port in: {} (error ignored)", subaction); return null; } } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static SubActionStruct decode_set_dst_port(String subaction, Logger log) { SubActionStruct sa = null; Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction); if (n.matches()) { if (n.group(1) != null) { try { short portnum = get_short(n.group(1)); OFActionTransportLayerDestination action = new OFActionTransportLayerDestination(); action.setTransportPort(portnum); log.debug("action {}", action); sa = new SubActionStruct(); sa.action = action; sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;; } catch (NumberFormatException e) { log.debug("Invalid dst-port in: {} (error ignored)", subaction); return null; } } } else { log.debug("Invalid action: '{}'", subaction); return null; } return sa; } private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) { byte[] macaddr = new byte[6]; for (int i=0; i<6; i++) { if (n.group(i+1) != null) { try { macaddr[i] = get_byte("0x" + n.group(i+1)); } catch (NumberFormatException e) { log.debug("Invalid src-mac in: '{}' (error ignored)", subaction); return null; } } else { log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction); return null; } } return macaddr; } private static int get_ip_addr(Matcher n, String subaction, Logger log) { int ipaddr = 0; for (int i=0; i<4; i++) { if (n.group(i+1) != null) { try { ipaddr = ipaddr<<8; ipaddr = ipaddr | get_int(n.group(i+1)); } catch (NumberFormatException e) { log.debug("Invalid src-ip in: '{}' (error ignored)", subaction); return 0; } } else { log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction); return 0; } } return ipaddr; } // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0) private static int get_int(String str) { return (int)Integer.decode(str); } // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0) private static short get_short(String str) { return (short)(int)Integer.decode(str); } // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0) private static byte get_byte(String str) { return Integer.decode(str).byteValue(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java0000664000175000017500000006460112041336206034332 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.staticflowentry.web.StaticFlowEntryWebRoutable; import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.IStorageSourceListener; import net.floodlightcontroller.storage.StorageException; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFFlowRemoved; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import org.openflow.protocol.factory.BasicFactory; import org.openflow.util.HexString; import org.openflow.util.U16; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @LogMessageCategory("Static Flow Pusher") /** * This module is responsible for maintaining a set of static flows on * switches. This is just a big 'ol dumb list of flows and something external * is responsible for ensuring they make sense for the network. */ public class StaticFlowEntryPusher implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, IStorageSourceListener, IOFMessageListener, IHAListener { protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class); public static final String StaticFlowName = "staticflowentry"; public static final int STATIC_FLOW_APP_ID = 10; public static final String TABLE_NAME = "controller_staticflowtableentry"; public static final String COLUMN_NAME = "name"; public static final String COLUMN_SWITCH = "switch_id"; public static final String COLUMN_ACTIVE = "active"; public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout"; public static final String COLUMN_HARD_TIMEOUT = "hard_timeout"; public static final String COLUMN_PRIORITY = "priority"; public static final String COLUMN_COOKIE = "cookie"; public static final String COLUMN_WILDCARD = "wildcards"; public static final String COLUMN_IN_PORT = "in_port"; public static final String COLUMN_DL_SRC = "dl_src"; public static final String COLUMN_DL_DST = "dl_dst"; public static final String COLUMN_DL_VLAN = "dl_vlan"; public static final String COLUMN_DL_VLAN_PCP = "dl_vlan_pcp"; public static final String COLUMN_DL_TYPE = "dl_type"; public static final String COLUMN_NW_TOS = "nw_tos"; public static final String COLUMN_NW_PROTO = "nw_proto"; public static final String COLUMN_NW_SRC = "nw_src"; // includes CIDR-style // netmask, e.g. // "128.8.128.0/24" public static final String COLUMN_NW_DST = "nw_dst"; public static final String COLUMN_TP_DST = "tp_dst"; public static final String COLUMN_TP_SRC = "tp_src"; public static final String COLUMN_ACTIONS = "actions"; public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH, COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT, COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_WILDCARD, COLUMN_IN_PORT, COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP, COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC, COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, COLUMN_ACTIONS }; protected IFloodlightProviderService floodlightProvider; protected IStorageSourceService storageSource; protected IRestApiService restApi; // Map> ; FlowMod can be null to indicate non-active protected Map> entriesFromStorage; // Entry Name -> DPID of Switch it's on protected Map entry2dpid; private BasicFactory ofMessageFactory; // Class to sort FlowMod's by priority, from lowest to highest class FlowModSorter implements Comparator { private String dpid; public FlowModSorter(String dpid) { this.dpid = dpid; } @Override public int compare(String o1, String o2) { OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1); OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2); if (f1 == null || f2 == null) // sort active=false flows by key return o1.compareTo(o2); return U16.f(f1.getPriority()) - U16.f(f2.getPriority()); } }; /** * used for debugging and unittests * @return the number of static flow entries as cached from storage */ public int countEntries() { int size = 0; if (entriesFromStorage == null) return 0; for (String ofswitch : entriesFromStorage.keySet()) size += entriesFromStorage.get(ofswitch).size(); return size; } public IFloodlightProviderService getFloodlightProvider() { return floodlightProvider; } public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { this.floodlightProvider = floodlightProvider; } public void setStorageSource(IStorageSourceService storageSource) { this.storageSource = storageSource; } /** * Reads from our entriesFromStorage for the specified switch and * sends the FlowMods down to the controller in sorted order. * * Sorted is important to maintain correctness of the switch: * if a packet would match both a lower and a higher priority * rule, then we want it to match the higher priority or nothing, * but never just the lower priority one. Inserting from high to * low priority fixes this. * * TODO consider adding a "block all" flow mod and then removing it * while starting up. * * @param sw The switch to send entries to */ protected void sendEntriesToSwitch(IOFSwitch sw) { String dpid = sw.getStringId(); if ((entriesFromStorage != null) && (entriesFromStorage.containsKey(dpid))) { Map entries = entriesFromStorage.get(dpid); List sortedList = new ArrayList(entries.keySet()); // weird that Collections.sort() returns void Collections.sort( sortedList, new FlowModSorter(dpid)); for (String entryName : sortedList) { OFFlowMod flowMod = entries.get(entryName); if (flowMod != null) { if (log.isDebugEnabled()) { log.debug("Pushing static entry {} for {}", dpid, entryName); } writeFlowModToSwitch(sw, flowMod); } } } } /** * Used only for bundle-local indexing * * @param map * @return */ protected Map computeEntry2DpidMap( Map> map) { Map ret = new HashMap(); for(String dpid : map.keySet()) { for( String entry: map.get(dpid).keySet()) ret.put(entry, dpid); } return ret; } /** * Read entries from storageSource, and store them in a hash * * @return */ @LogMessageDoc(level="ERROR", message="failed to access storage: {reason}", explanation="Could not retrieve static flows from the system " + "database", recommendation=LogMessageDoc.CHECK_CONTROLLER) private Map> readEntriesFromStorage() { Map> entries = new ConcurrentHashMap>(); try { Map row; // null1=no predicate, null2=no ordering IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, ColumnNames, null, null); for (Iterator it = resultSet.iterator(); it.hasNext();) { row = it.next().getRow(); parseRow(row, entries); } } catch (StorageException e) { log.error("failed to access storage: {}", e.getMessage()); // if the table doesn't exist, then wait to populate later via // setStorageSource() } return entries; } /** * Take a single row, turn it into a flowMod, and add it to the * entries{$dpid}.{$entryName}=FlowMod * * IF an entry is in active, mark it with FlowMod = null * * @param row * @param entries */ void parseRow(Map row, Map> entries) { String switchName = null; String entryName = null; StringBuffer matchString = new StringBuffer(); if (ofMessageFactory == null) // lazy init ofMessageFactory = new BasicFactory(); OFFlowMod flowMod = (OFFlowMod) ofMessageFactory .getMessage(OFType.FLOW_MOD); if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) { log.debug( "skipping entry with missing required 'switch' or 'name' entry: {}", row); return; } // most error checking done with ClassCastException try { // first, snag the required entries, for debugging info switchName = (String) row.get(COLUMN_SWITCH); entryName = (String) row.get(COLUMN_NAME); if (!entries.containsKey(switchName)) entries.put(switchName, new HashMap()); StaticFlowEntries.initDefaultFlowMod(flowMod, entryName); for (String key : row.keySet()) { if (row.get(key) == null) continue; if ( key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME) || key.equals("id")) continue; // already handled // explicitly ignore timeouts and wildcards if ( key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT) || key.equals(COLUMN_WILDCARD)) continue; if ( key.equals(COLUMN_ACTIVE)) { if (! Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) { log.debug("skipping inactive entry {} for switch {}", entryName, switchName); entries.get(switchName).put(entryName, null); // mark this an inactive return; } } else if ( key.equals(COLUMN_ACTIONS)){ StaticFlowEntries.parseActionString(flowMod, (String) row.get(COLUMN_ACTIONS), log); } else if ( key.equals(COLUMN_COOKIE)) { flowMod.setCookie( StaticFlowEntries.computeEntryCookie(flowMod, Integer.valueOf((String) row.get(COLUMN_COOKIE)), entryName) ); } else if ( key.equals(COLUMN_PRIORITY)) { flowMod.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY)))); } else { // the rest of the keys are for OFMatch().fromString() if (matchString.length() > 0) matchString.append(","); matchString.append(key + "=" + row.get(key).toString()); } } } catch (ClassCastException e) { if (entryName != null && switchName != null) log.debug( "skipping entry {} on switch {} with bad data : " + e.getMessage(), entryName, switchName); else log.debug("skipping entry with bad data: {} :: {} ", e.getMessage(), e.getStackTrace()); } OFMatch ofMatch = new OFMatch(); String match = matchString.toString(); try { ofMatch.fromString(match); } catch (IllegalArgumentException e) { log.debug( "ignoring flow entry {} on switch {} with illegal OFMatch() key: " + match, entryName, switchName); return; } flowMod.setMatch(ofMatch); entries.get(switchName).put(entryName, flowMod); } @Override public void addedSwitch(IOFSwitch sw) { log.debug("addedSwitch {}; processing its static entries", sw); sendEntriesToSwitch(sw); } @Override public void removedSwitch(IOFSwitch sw) { log.debug("removedSwitch {}", sw); // do NOT delete from our internal state; we're tracking the rules, // not the switches } @Override public void switchPortChanged(Long switchId) { // no-op } /** * This handles both rowInsert() and rowUpdate() */ @Override public void rowsModified(String tableName, Set rowKeys) { log.debug("Modifying Table {}", tableName); HashMap> entriesToAdd = new HashMap>(); // build up list of what was added for(Object key: rowKeys) { IResultSet resultSet = storageSource.getRow(tableName, key); for (Iterator it = resultSet.iterator(); it.hasNext();) { Map row = it.next().getRow(); parseRow(row, entriesToAdd); } } // batch updates by switch and blast them out for (String dpid : entriesToAdd.keySet()) { if (!entriesFromStorage.containsKey(dpid)) entriesFromStorage.put(dpid, new HashMap()); List outQueue = new ArrayList(); for(String entry : entriesToAdd.get(dpid).keySet()) { OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry); OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry); if (oldFlowMod != null) { // remove any pre-existing rule oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); outQueue.add(oldFlowMod); } if (newFlowMod != null) { entriesFromStorage.get(dpid).put(entry, newFlowMod); outQueue.add(newFlowMod); entry2dpid.put(entry, dpid); } else { entriesFromStorage.get(dpid).remove(entry); entry2dpid.remove(entry); } } writeOFMessagesToSwitch(HexString.toLong(dpid), outQueue); } } @Override public void rowsDeleted(String tableName, Set rowKeys) { if (log.isDebugEnabled()) { log.debug("deleting from Table {}", tableName); } for(Object obj : rowKeys) { if (!(obj instanceof String)) { log.debug("tried to delete non-string key {}; ignoring", obj); continue; } deleteStaticFlowEntry((String) obj); } } @LogMessageDoc(level="ERROR", message="inconsistent internal state: no switch has rule {rule}", explanation="Inconsistent internat state discovered while " + "deleting a static flow rule", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) private boolean deleteStaticFlowEntry(String entryName) { String dpid = entry2dpid.get(entryName); if (log.isDebugEnabled()) { log.debug("Deleting flow {} for switch {}", entryName, dpid); } if (dpid == null) { log.error("inconsistent internal state: no switch has rule {}", entryName); return false; } // send flow_mod delete OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName); flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); if (entriesFromStorage.containsKey(dpid) && entriesFromStorage.get(dpid).containsKey(entryName)) { entriesFromStorage.get(dpid).remove(entryName); } else { log.debug("Tried to delete non-existent entry {} for switch {}", entryName, dpid); return false; } writeFlowModToSwitch(HexString.toLong(dpid), flowMod); return true; } /** * Writes a list of OFMessages to a switch * @param dpid The datapath ID of the switch to write to * @param messages The list of OFMessages to write. */ @LogMessageDoc(level="ERROR", message="Tried to write to switch {switch} but got {error}", explanation="An I/O error occured while trying to write a " + "static flow to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) private void writeOFMessagesToSwitch(long dpid, List messages) { IOFSwitch ofswitch = floodlightProvider.getSwitches().get(dpid); if (ofswitch != null) { // is the switch connected try { if (log.isDebugEnabled()) { log.debug("Sending {} new entries to {}", messages.size(), dpid); } ofswitch.write(messages, null); ofswitch.flush(); } catch (IOException e) { log.error("Tried to write to switch {} but got {}", dpid, e.getMessage()); } } } /** * Writes an OFFlowMod to a switch. It checks to make sure the switch * exists before it sends * @param dpid The data to write the flow mod to * @param flowMod The OFFlowMod to write */ private void writeFlowModToSwitch(long dpid, OFFlowMod flowMod) { Map switches = floodlightProvider.getSwitches(); IOFSwitch ofSwitch = switches.get(dpid); if (ofSwitch == null) { if (log.isDebugEnabled()) { log.debug("Not deleting key {} :: switch {} not connected", dpid); } return; } writeFlowModToSwitch(ofSwitch, flowMod); } /** * Writes an OFFlowMod to a switch * @param sw The IOFSwitch to write to * @param flowMod The OFFlowMod to write */ @LogMessageDoc(level="ERROR", message="Tried to write OFFlowMod to {switch} but got {error}", explanation="An I/O error occured while trying to write a " + "static flow to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) { try { sw.write(flowMod, null); sw.flush(); } catch (IOException e) { log.error("Tried to write OFFlowMod to {} but failed: {}", HexString.toHexString(sw.getId()), e.getMessage()); } } @Override public String getName() { return StaticFlowName; } @Override @LogMessageDoc(level="ERROR", message="Got a FlowRemove message for a infinite " + "timeout flow: {flow} from switch {switch}", explanation="Flows with infinite timeouts should not expire. " + "The switch has expired the flow anyway.", recommendation=LogMessageDoc.REPORT_SWITCH_BUG) public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case FLOW_REMOVED: break; default: return Command.CONTINUE; } OFFlowRemoved flowRemoved = (OFFlowRemoved) msg; long cookie = flowRemoved.getCookie(); /** * This is just to sanity check our assumption that static flows * never expire. */ if( AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) { if (flowRemoved.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE) log.error("Got a FlowRemove message for a infinite " + "timeout flow: {} from switch {}", msg, sw); return Command.STOP; // only for us } else return Command.CONTINUE; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; // no dependency for non-packet in } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; // no dependency for non-packet in } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IStaticFlowEntryPusherService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IStaticFlowEntryPusherService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IStorageSourceService.class); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); storageSource = context.getServiceImpl(IStorageSourceService.class); restApi = context.getServiceImpl(IRestApiService.class); } @Override public void startUp(FloodlightModuleContext context) { floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this); floodlightProvider.addOFSwitchListener(this); floodlightProvider.addHAListener(this); // assumes no switches connected at startup() storageSource.createTable(TABLE_NAME, null); storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME); storageSource.addListener(TABLE_NAME, this); entriesFromStorage = readEntriesFromStorage(); entry2dpid = computeEntry2DpidMap(entriesFromStorage); restApi.addRestletRoutable(new StaticFlowEntryWebRoutable()); } // IStaticFlowEntryPusherService methods @Override public void addFlow(String name, OFFlowMod fm, String swDpid) { Map fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid, name); entry2dpid.put(name, swDpid); Map switchEntries = entriesFromStorage.get(swDpid); if (switchEntries == null) { switchEntries = new HashMap(); entriesFromStorage.put(swDpid, switchEntries); } switchEntries.put(name, fm); storageSource.insertRowAsync(TABLE_NAME, fmMap); } @Override public void deleteFlow(String name) { storageSource.deleteRowAsync(TABLE_NAME, name); // TODO - What if there is a delay in storage? } @Override public void deleteAllFlows() { for (String entry : entry2dpid.keySet()) { deleteFlow(entry); } } @Override public void deleteFlowsForSwitch(long dpid) { String sDpid = HexString.toHexString(dpid); for (Entry e : entry2dpid.entrySet()) { if (e.getValue().equals(sDpid)) deleteFlow(e.getKey()); } } @Override public Map> getFlows() { return entriesFromStorage; } @Override public Map getFlows(String dpid) { return entriesFromStorage.get(dpid); } // IHAListener @Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case MASTER: if (oldRole == Role.SLAVE) { log.debug("Re-reading static flows from storage due " + "to HA change from SLAVE->MASTER"); entriesFromStorage = readEntriesFromStorage(); entry2dpid = computeEntry2DpidMap(entriesFromStorage); } break; case SLAVE: log.debug("Clearing in-memory flows due to " + "HA change to SLAVE"); entry2dpid.clear(); entriesFromStorage.clear(); break; default: break; } } @Override public void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { // ignore } } floodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/0000775000175000017500000000000012041336206027745 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesRes0000664000175000017500000000267512041336206034734 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry.web; import net.floodlightcontroller.core.web.ControllerSwitchesResource; import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; import org.openflow.util.HexString; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ClearStaticFlowEntriesResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(ClearStaticFlowEntriesResource.class); @Get public void ClearStaticFlowEntries() { IStaticFlowEntryPusherService sfpService = (IStaticFlowEntryPusherService)getContext().getAttributes(). get(IStaticFlowEntryPusherService.class.getCanonicalName()); String param = (String) getRequestAttributes().get("switch"); if (log.isDebugEnabled()) log.debug("Clearing all static flow entires for switch: " + param); if (param.toLowerCase().equals("all")) { sfpService.deleteAllFlows(); } else { try { sfpService.deleteFlowsForSwitch(HexString.toLong(param)); } catch (NumberFormatException e){ setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ControllerSwitchesResource.DPID_ERROR); return; } } } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesReso0000664000175000017500000000326512041336206034774 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry.web; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.core.web.ControllerSwitchesResource; import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; import org.openflow.protocol.OFFlowMod; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ListStaticFlowEntriesResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(ListStaticFlowEntriesResource.class); @Get public Map> ListStaticFlowEntries() { IStaticFlowEntryPusherService sfpService = (IStaticFlowEntryPusherService)getContext().getAttributes(). get(IStaticFlowEntryPusherService.class.getCanonicalName()); String param = (String) getRequestAttributes().get("switch"); if (log.isDebugEnabled()) log.debug("Listing all static flow entires for switch: " + param); if (param.toLowerCase().equals("all")) { return sfpService.getFlows(); } else { try { Map> retMap = new HashMap>(); retMap.put(param, sfpService.getFlows(param)); return retMap; } catch (NumberFormatException e){ setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ControllerSwitchesResource.DPID_ERROR); } } return null; } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryWebRoutable.javafloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryWebRoutabl0000664000175000017500000000157212041336206034765 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry.web; import net.floodlightcontroller.restserver.RestletRoutable; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; public class StaticFlowEntryWebRoutable implements RestletRoutable { /** * Create the Restlet router and bind to the proper resources. */ @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/json", StaticFlowEntryPusherResource.class); router.attach("/clear/{switch}/json", ClearStaticFlowEntriesResource.class); router.attach("/list/{switch}/json", ListStaticFlowEntriesResource.class); return router; } /** * Set the base path for the Topology */ @Override public String basePath() { return "/wm/staticflowentrypusher"; } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryPusherResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryPusherReso0000664000175000017500000001334112041336206035013 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.staticflowentry.web; import java.io.IOException; import java.util.Map; import org.restlet.resource.Delete; import org.restlet.resource.Post; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.staticflowentry.StaticFlowEntries; import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; import net.floodlightcontroller.storage.IStorageSourceService; /** * Pushes a static flow entry to the storage source * @author alexreimers * */ @LogMessageCategory("Static Flow Pusher") public class StaticFlowEntryPusherResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusherResource.class); /** * Checks to see if the user matches IP information without * checking for the correct ether-type (2048). * @param rows The Map that is a string representation of * the static flow. * @reutrn True if they checked the ether-type, false otherwise */ private boolean checkMatchIp(Map rows) { boolean matchEther = false; String val = (String) rows.get(StaticFlowEntryPusher.COLUMN_DL_TYPE); if (val != null) { int type = 0; // check both hex and decimal if (val.startsWith("0x")) { type = Integer.parseInt(val.substring(2), 16); } else { try { type = Integer.parseInt(val); } catch (NumberFormatException e) { /* fail silently */} } if (type == 2048) matchEther = true; } if ((rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_DST) || rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_SRC) || rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_PROTO) || rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_TOS)) && (matchEther == false)) return false; return true; } /** * Takes a Static Flow Pusher string in JSON format and parses it into * our database schema then pushes it to the database. * @param fmJson The Static Flow Pusher entry in JSON format. * @return A string status message */ @Post @LogMessageDoc(level="ERROR", message="Error parsing push flow mod request: {request}", explanation="An invalid request was sent to static flow pusher", recommendation="Fix the format of the static flow mod request") public String store(String fmJson) { IStorageSourceService storageSource = (IStorageSourceService)getContext().getAttributes(). get(IStorageSourceService.class.getCanonicalName()); Map rowValues; try { rowValues = StaticFlowEntries.jsonToStorageEntry(fmJson); String status = null; if (!checkMatchIp(rowValues)) { status = "Warning! Pushing a static flow entry that matches IP " + "fields without matching for IP payload (ether-type 2048) will cause " + "the switch to wildcard higher level fields."; log.error(status); } else { status = "Entry pushed"; } storageSource.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, rowValues); return ("{\"status\" : \"" + status + "\"}"); } catch (IOException e) { log.error("Error parsing push flow mod request: " + fmJson, e); e.printStackTrace(); return "{\"status\" : \"Error! Could not parse flod mod, see log for details.\"}"; } } @Delete @LogMessageDoc(level="ERROR", message="Error deleting flow mod request: {request}", explanation="An invalid delete request was sent to static flow pusher", recommendation="Fix the format of the static flow mod request") public String del(String fmJson) { IStorageSourceService storageSource = (IStorageSourceService)getContext().getAttributes(). get(IStorageSourceService.class.getCanonicalName()); String fmName = null; if (fmJson == null) { return "{\"status\" : \"Error! No data posted.\"}"; } try { fmName = StaticFlowEntries.getEntryNameFromJson(fmJson); if (fmName == null) { return "{\"status\" : \"Error deleting entry, no name provided\"}"; } } catch (IOException e) { log.error("Error deleting flow mod request: " + fmJson, e); e.printStackTrace(); return "{\"status\" : \"Error deleting entry, see log for details\"}"; } storageSource.deleteRowAsync(StaticFlowEntryPusher.TABLE_NAME, fmName); return "{\"status\" : \"Entry " + fmName + " deleted\"}"; } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.javafloodlight-0.90/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService0000664000175000017500000000225712041336206035043 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry; import java.util.Map; import org.openflow.protocol.OFFlowMod; import net.floodlightcontroller.core.module.IFloodlightService; public interface IStaticFlowEntryPusherService extends IFloodlightService { /** * Adds a static flow. * @param name Name of the flow mod. Must be unique. * @param fm The flow to push. * @param swDpid The switch DPID to push it to, in 00:00:00:00:00:00:00:01 notation. */ public void addFlow(String name, OFFlowMod fm, String swDpid); /** * Deletes a static flow * @param name The name of the static flow to delete. */ public void deleteFlow(String name); /** * Deletes all static flows for a practicular switch * @param dpid The DPID of the switch to delete flows for. */ public void deleteFlowsForSwitch(long dpid); /** * Deletes all flows. */ public void deleteAllFlows(); /** * Gets all list of all flows */ public Map> getFlows(); /** * Gets a list of flows by switch */ public Map getFlows(String dpid); } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/0000775000175000017500000000000012041336206025176 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/packet/BasePacket.java0000664000175000017500000000577612041336206030062 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public abstract class BasePacket implements IPacket { protected IPacket parent; protected IPacket payload; /** * @return the parent */ @Override public IPacket getParent() { return parent; } /** * @param parent the parent to set */ @Override public IPacket setParent(IPacket parent) { this.parent = parent; return this; } /** * @return the payload */ @Override public IPacket getPayload() { return payload; } /** * @param payload the payload to set */ @Override public IPacket setPayload(IPacket payload) { this.payload = payload; return this; } @Override public void resetChecksum() { if (this.parent != null) this.parent.resetChecksum(); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 6733; int result = 1; result = prime * result + ((payload == null) ? 0 : payload.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof BasePacket)) return false; BasePacket other = (BasePacket) obj; if (payload == null) { if (other.payload != null) return false; } else if (!payload.equals(other.payload)) return false; return true; } @Override public Object clone() { IPacket pkt; try { pkt = this.getClass().newInstance(); } catch (Exception e) { throw new RuntimeException("Could not clone packet"); } // TODO: we are using serialize()/deserialize() to perform the // cloning. Not the most efficient way but simple. We can revisit // if we hit performance problems. byte[] data = this.serialize(); pkt.deserialize(this.serialize(), 0, data.length); pkt.setParent(this.parent); return pkt; } }floodlight-0.90/src/main/java/net/floodlightcontroller/packet/IPacket.java0000664000175000017500000000370212041336206027363 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IPacket { /** * * @return */ public IPacket getPayload(); /** * * @param packet * @return */ public IPacket setPayload(IPacket packet); /** * * @return */ public IPacket getParent(); /** * * @param packet * @return */ public IPacket setParent(IPacket packet); /** * Reset any checksums as needed, and call resetChecksum on all parents */ public void resetChecksum(); /** * Sets all payloads parent packet if applicable, then serializes this * packet and all payloads * @return a byte[] containing this packet and payloads */ public byte[] serialize(); /** * Deserializes this packet layer and all possible payloads * @param data * @param offset offset to start deserializing from * @param length length of the data to deserialize * @return the deserialized data */ public IPacket deserialize(byte[] data, int offset, int length); /** Clone this packet and its payload packet but not its parent. * * @return */ public Object clone(); } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/IPv4.java0000664000175000017500000003673412041336206026640 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class IPv4 extends BasePacket { public static final byte PROTOCOL_ICMP = 0x1; public static final byte PROTOCOL_TCP = 0x6; public static final byte PROTOCOL_UDP = 0x11; public static Map> protocolClassMap; static { protocolClassMap = new HashMap>(); protocolClassMap.put(PROTOCOL_ICMP, ICMP.class); protocolClassMap.put(PROTOCOL_TCP, TCP.class); protocolClassMap.put(PROTOCOL_UDP, UDP.class); } protected byte version; protected byte headerLength; protected byte diffServ; protected short totalLength; protected short identification; protected byte flags; protected short fragmentOffset; protected byte ttl; protected byte protocol; protected short checksum; protected int sourceAddress; protected int destinationAddress; protected byte[] options; protected boolean isTruncated; /** * Default constructor that sets the version to 4. */ public IPv4() { super(); this.version = 4; isTruncated = false; } /** * @return the version */ public byte getVersion() { return version; } /** * @param version the version to set */ public IPv4 setVersion(byte version) { this.version = version; return this; } /** * @return the headerLength */ public byte getHeaderLength() { return headerLength; } /** * @return the diffServ */ public byte getDiffServ() { return diffServ; } /** * @param diffServ the diffServ to set */ public IPv4 setDiffServ(byte diffServ) { this.diffServ = diffServ; return this; } /** * @return the totalLength */ public short getTotalLength() { return totalLength; } /** * @return the identification */ public short getIdentification() { return identification; } public boolean isTruncated() { return isTruncated; } public void setTruncated(boolean isTruncated) { this.isTruncated = isTruncated; } /** * @param identification the identification to set */ public IPv4 setIdentification(short identification) { this.identification = identification; return this; } /** * @return the flags */ public byte getFlags() { return flags; } /** * @param flags the flags to set */ public IPv4 setFlags(byte flags) { this.flags = flags; return this; } /** * @return the fragmentOffset */ public short getFragmentOffset() { return fragmentOffset; } /** * @param fragmentOffset the fragmentOffset to set */ public IPv4 setFragmentOffset(short fragmentOffset) { this.fragmentOffset = fragmentOffset; return this; } /** * @return the ttl */ public byte getTtl() { return ttl; } /** * @param ttl the ttl to set */ public IPv4 setTtl(byte ttl) { this.ttl = ttl; return this; } /** * @return the protocol */ public byte getProtocol() { return protocol; } /** * @param protocol the protocol to set */ public IPv4 setProtocol(byte protocol) { this.protocol = protocol; return this; } /** * @return the checksum */ public short getChecksum() { return checksum; } /** * @param checksum the checksum to set */ public IPv4 setChecksum(short checksum) { this.checksum = checksum; return this; } @Override public void resetChecksum() { this.checksum = 0; super.resetChecksum(); } /** * @return the sourceAddress */ public int getSourceAddress() { return sourceAddress; } /** * @param sourceAddress the sourceAddress to set */ public IPv4 setSourceAddress(int sourceAddress) { this.sourceAddress = sourceAddress; return this; } /** * @param sourceAddress the sourceAddress to set */ public IPv4 setSourceAddress(String sourceAddress) { this.sourceAddress = IPv4.toIPv4Address(sourceAddress); return this; } /** * @return the destinationAddress */ public int getDestinationAddress() { return destinationAddress; } /** * @param destinationAddress the destinationAddress to set */ public IPv4 setDestinationAddress(int destinationAddress) { this.destinationAddress = destinationAddress; return this; } /** * @param destinationAddress the destinationAddress to set */ public IPv4 setDestinationAddress(String destinationAddress) { this.destinationAddress = IPv4.toIPv4Address(destinationAddress); return this; } /** * @return the options */ public byte[] getOptions() { return options; } /** * @param options the options to set */ public IPv4 setOptions(byte[] options) { if (options != null && (options.length % 4) > 0) throw new IllegalArgumentException( "Options length must be a multiple of 4"); this.options = options; return this; } /** * Serializes the packet. Will compute and set the following fields if they * are set to specific values at the time serialize is called: * -checksum : 0 * -headerLength : 0 * -totalLength : 0 */ public byte[] serialize() { byte[] payloadData = null; if (payload != null) { payload.setParent(this); payloadData = payload.serialize(); } int optionsLength = 0; if (this.options != null) optionsLength = this.options.length / 4; this.headerLength = (byte) (5 + optionsLength); this.totalLength = (short) (this.headerLength * 4 + ((payloadData == null) ? 0 : payloadData.length)); byte[] data = new byte[this.totalLength]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put((byte) (((this.version & 0xf) << 4) | (this.headerLength & 0xf))); bb.put(this.diffServ); bb.putShort(this.totalLength); bb.putShort(this.identification); bb.putShort((short) (((this.flags & 0x7) << 13) | (this.fragmentOffset & 0x1fff))); bb.put(this.ttl); bb.put(this.protocol); bb.putShort(this.checksum); bb.putInt(this.sourceAddress); bb.putInt(this.destinationAddress); if (this.options != null) bb.put(this.options); if (payloadData != null) bb.put(payloadData); // compute checksum if needed if (this.checksum == 0) { bb.rewind(); int accumulation = 0; for (int i = 0; i < this.headerLength * 2; ++i) { accumulation += 0xffff & bb.getShort(); } accumulation = ((accumulation >> 16) & 0xffff) + (accumulation & 0xffff); this.checksum = (short) (~accumulation & 0xffff); bb.putShort(10, this.checksum); } return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); short sscratch; this.version = bb.get(); this.headerLength = (byte) (this.version & 0xf); this.version = (byte) ((this.version >> 4) & 0xf); this.diffServ = bb.get(); this.totalLength = bb.getShort(); this.identification = bb.getShort(); sscratch = bb.getShort(); this.flags = (byte) ((sscratch >> 13) & 0x7); this.fragmentOffset = (short) (sscratch & 0x1fff); this.ttl = bb.get(); this.protocol = bb.get(); this.checksum = bb.getShort(); this.sourceAddress = bb.getInt(); this.destinationAddress = bb.getInt(); if (this.headerLength > 5) { int optionsLength = (this.headerLength - 5) * 4; this.options = new byte[optionsLength]; bb.get(this.options); } IPacket payload; if (IPv4.protocolClassMap.containsKey(this.protocol)) { Class clazz = IPv4.protocolClassMap.get(this.protocol); try { payload = clazz.newInstance(); } catch (Exception e) { throw new RuntimeException("Error parsing payload for IPv4 packet", e); } } else { payload = new Data(); } this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position()); this.payload.setParent(this); if (this.totalLength != length) this.isTruncated = true; else this.isTruncated = false; return this; } /** * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and * returns the corresponding 32 bit integer. * @param ipAddress * @return */ public static int toIPv4Address(String ipAddress) { if (ipAddress == null) throw new IllegalArgumentException("Specified IPv4 address must" + "contain 4 sets of numerical digits separated by periods"); String[] octets = ipAddress.split("\\."); if (octets.length != 4) throw new IllegalArgumentException("Specified IPv4 address must" + "contain 4 sets of numerical digits separated by periods"); int result = 0; for (int i = 0; i < 4; ++i) { result |= Integer.valueOf(octets[i]) << ((3-i)*8); } return result; } /** * Accepts an IPv4 address in a byte array and returns the corresponding * 32-bit integer value. * @param ipAddress * @return */ public static int toIPv4Address(byte[] ipAddress) { int ip = 0; for (int i = 0; i < 4; i++) { int t = (ipAddress[i] & 0xff) << ((3-i)*8); ip |= t; } return ip; } /** * Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx * ie 192.168.0.1 * * @param ipAddress * @return */ public static String fromIPv4Address(int ipAddress) { StringBuffer sb = new StringBuffer(); int result = 0; for (int i = 0; i < 4; ++i) { result = (ipAddress >> ((3-i)*8)) & 0xff; sb.append(Integer.valueOf(result).toString()); if (i != 3) sb.append("."); } return sb.toString(); } /** * Accepts a collection of IPv4 addresses as integers and returns a single * String useful in toString method's containing collections of IP * addresses. * * @param ipAddresses collection * @return */ public static String fromIPv4AddressCollection(Collection ipAddresses) { if (ipAddresses == null) return "null"; StringBuffer sb = new StringBuffer(); sb.append("["); for (Integer ip : ipAddresses) { sb.append(fromIPv4Address(ip)); sb.append(","); } sb.replace(sb.length()-1, sb.length(), "]"); return sb.toString(); } /** * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and * returns the corresponding byte array. * @param ipAddress The IP address in the form xx.xxx.xxx.xxx. * @return The IP address separated into bytes */ public static byte[] toIPv4AddressBytes(String ipAddress) { String[] octets = ipAddress.split("\\."); if (octets.length != 4) throw new IllegalArgumentException("Specified IPv4 address must" + "contain 4 sets of numerical digits separated by periods"); byte[] result = new byte[4]; for (int i = 0; i < 4; ++i) { result[i] = Integer.valueOf(octets[i]).byteValue(); } return result; } /** * Accepts an IPv4 address in the form of an integer and * returns the corresponding byte array. * @param ipAddress The IP address as an integer. * @return The IP address separated into bytes. */ public static byte[] toIPv4AddressBytes(int ipAddress) { return new byte[] { (byte)(ipAddress >>> 24), (byte)(ipAddress >>> 16), (byte)(ipAddress >>> 8), (byte)ipAddress}; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 2521; int result = super.hashCode(); result = prime * result + checksum; result = prime * result + destinationAddress; result = prime * result + diffServ; result = prime * result + flags; result = prime * result + fragmentOffset; result = prime * result + headerLength; result = prime * result + identification; result = prime * result + Arrays.hashCode(options); result = prime * result + protocol; result = prime * result + sourceAddress; result = prime * result + totalLength; result = prime * result + ttl; result = prime * result + version; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof IPv4)) return false; IPv4 other = (IPv4) obj; if (checksum != other.checksum) return false; if (destinationAddress != other.destinationAddress) return false; if (diffServ != other.diffServ) return false; if (flags != other.flags) return false; if (fragmentOffset != other.fragmentOffset) return false; if (headerLength != other.headerLength) return false; if (identification != other.identification) return false; if (!Arrays.equals(options, other.options)) return false; if (protocol != other.protocol) return false; if (sourceAddress != other.sourceAddress) return false; if (totalLength != other.totalLength) return false; if (ttl != other.ttl) return false; if (version != other.version) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/ARP.java0000664000175000017500000002373012041336206026470 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class ARP extends BasePacket { public static short HW_TYPE_ETHERNET = 0x1; public static short PROTO_TYPE_IP = 0x800; public static short OP_REQUEST = 0x1; public static short OP_REPLY = 0x2; public static short OP_RARP_REQUEST = 0x3; public static short OP_RARP_REPLY = 0x4; protected short hardwareType; protected short protocolType; protected byte hardwareAddressLength; protected byte protocolAddressLength; protected short opCode; protected byte[] senderHardwareAddress; protected byte[] senderProtocolAddress; protected byte[] targetHardwareAddress; protected byte[] targetProtocolAddress; /** * @return the hardwareType */ public short getHardwareType() { return hardwareType; } /** * @param hardwareType the hardwareType to set */ public ARP setHardwareType(short hardwareType) { this.hardwareType = hardwareType; return this; } /** * @return the protocolType */ public short getProtocolType() { return protocolType; } /** * @param protocolType the protocolType to set */ public ARP setProtocolType(short protocolType) { this.protocolType = protocolType; return this; } /** * @return the hardwareAddressLength */ public byte getHardwareAddressLength() { return hardwareAddressLength; } /** * @param hardwareAddressLength the hardwareAddressLength to set */ public ARP setHardwareAddressLength(byte hardwareAddressLength) { this.hardwareAddressLength = hardwareAddressLength; return this; } /** * @return the protocolAddressLength */ public byte getProtocolAddressLength() { return protocolAddressLength; } /** * @param protocolAddressLength the protocolAddressLength to set */ public ARP setProtocolAddressLength(byte protocolAddressLength) { this.protocolAddressLength = protocolAddressLength; return this; } /** * @return the opCode */ public short getOpCode() { return opCode; } /** * @param opCode the opCode to set */ public ARP setOpCode(short opCode) { this.opCode = opCode; return this; } /** * @return the senderHardwareAddress */ public byte[] getSenderHardwareAddress() { return senderHardwareAddress; } /** * @param senderHardwareAddress the senderHardwareAddress to set */ public ARP setSenderHardwareAddress(byte[] senderHardwareAddress) { this.senderHardwareAddress = senderHardwareAddress; return this; } /** * @return the senderProtocolAddress */ public byte[] getSenderProtocolAddress() { return senderProtocolAddress; } /** * @param senderProtocolAddress the senderProtocolAddress to set */ public ARP setSenderProtocolAddress(byte[] senderProtocolAddress) { this.senderProtocolAddress = senderProtocolAddress; return this; } public ARP setSenderProtocolAddress(int address) { this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address).array(); return this; } /** * @return the targetHardwareAddress */ public byte[] getTargetHardwareAddress() { return targetHardwareAddress; } /** * @param targetHardwareAddress the targetHardwareAddress to set */ public ARP setTargetHardwareAddress(byte[] targetHardwareAddress) { this.targetHardwareAddress = targetHardwareAddress; return this; } /** * @return the targetProtocolAddress */ public byte[] getTargetProtocolAddress() { return targetProtocolAddress; } /** * @return True if gratuitous ARP (SPA = TPA), false otherwise */ public boolean isGratuitous() { assert(senderProtocolAddress.length == targetProtocolAddress.length); int indx = 0; while (indx < senderProtocolAddress.length) { if (senderProtocolAddress[indx] != targetProtocolAddress[indx]) { return false; } indx++; } return true; } /** * @param targetProtocolAddress the targetProtocolAddress to set */ public ARP setTargetProtocolAddress(byte[] targetProtocolAddress) { this.targetProtocolAddress = targetProtocolAddress; return this; } public ARP setTargetProtocolAddress(int address) { this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address).array(); return this; } @Override public byte[] serialize() { int length = 8 + (2 * (0xff & this.hardwareAddressLength)) + (2 * (0xff & this.protocolAddressLength)); byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putShort(this.hardwareType); bb.putShort(this.protocolType); bb.put(this.hardwareAddressLength); bb.put(this.protocolAddressLength); bb.putShort(this.opCode); bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength); bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength); bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength); bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength); return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); this.hardwareType = bb.getShort(); this.protocolType = bb.getShort(); this.hardwareAddressLength = bb.get(); this.protocolAddressLength = bb.get(); this.opCode = bb.getShort(); this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength]; bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length); this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength]; bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length); this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength]; bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length); this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength]; bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length); return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 13121; int result = super.hashCode(); result = prime * result + hardwareAddressLength; result = prime * result + hardwareType; result = prime * result + opCode; result = prime * result + protocolAddressLength; result = prime * result + protocolType; result = prime * result + Arrays.hashCode(senderHardwareAddress); result = prime * result + Arrays.hashCode(senderProtocolAddress); result = prime * result + Arrays.hashCode(targetHardwareAddress); result = prime * result + Arrays.hashCode(targetProtocolAddress); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof ARP)) return false; ARP other = (ARP) obj; if (hardwareAddressLength != other.hardwareAddressLength) return false; if (hardwareType != other.hardwareType) return false; if (opCode != other.opCode) return false; if (protocolAddressLength != other.protocolAddressLength) return false; if (protocolType != other.protocolType) return false; if (!Arrays.equals(senderHardwareAddress, other.senderHardwareAddress)) return false; if (!Arrays.equals(senderProtocolAddress, other.senderProtocolAddress)) return false; if (!Arrays.equals(targetHardwareAddress, other.targetHardwareAddress)) return false; if (!Arrays.equals(targetProtocolAddress, other.targetProtocolAddress)) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "ARP [hardwareType=" + hardwareType + ", protocolType=" + protocolType + ", hardwareAddressLength=" + hardwareAddressLength + ", protocolAddressLength=" + protocolAddressLength + ", opCode=" + opCode + ", senderHardwareAddress=" + Arrays.toString(senderHardwareAddress) + ", senderProtocolAddress=" + Arrays.toString(senderProtocolAddress) + ", targetHardwareAddress=" + Arrays.toString(targetHardwareAddress) + ", targetProtocolAddress=" + Arrays.toString(targetProtocolAddress) + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/Data.java0000664000175000017500000000430512041336206026714 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.util.Arrays; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class Data extends BasePacket { protected byte[] data; /** * */ public Data() { } /** * @param data */ public Data(byte[] data) { this.data = data; } /** * @return the data */ public byte[] getData() { return data; } /** * @param data the data to set */ public Data setData(byte[] data) { this.data = data; return this; } public byte[] serialize() { return this.data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { this.data = Arrays.copyOfRange(data, offset, data.length); return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 1571; int result = super.hashCode(); result = prime * result + Arrays.hashCode(data); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof Data)) return false; Data other = (Data) obj; if (!Arrays.equals(data, other.data)) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/TCP.java0000664000175000017500000002124712041336206026475 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; /** * * @author shudong.zhou@bigswitch.com */ public class TCP extends BasePacket { protected short sourcePort; protected short destinationPort; protected int sequence; protected int acknowledge; protected byte dataOffset; protected short flags; protected short windowSize; protected short checksum; protected short urgentPointer; protected byte[] options; /** * @return the sourcePort */ public short getSourcePort() { return sourcePort; } /** * @param sourcePort the sourcePort to set */ public TCP setSourcePort(short sourcePort) { this.sourcePort = sourcePort; return this; } /** * @return the destinationPort */ public short getDestinationPort() { return destinationPort; } /** * @param destinationPort the destinationPort to set */ public TCP setDestinationPort(short destinationPort) { this.destinationPort = destinationPort; return this; } /** * @return the checksum */ public short getChecksum() { return checksum; } public int getSequence() { return this.sequence; } public TCP setSequence(int seq) { this.sequence = seq; return this; } public int getAcknowledge() { return this.acknowledge; } public TCP setAcknowledge(int ack) { this.acknowledge = ack; return this; } public byte getDataOffset() { return this.dataOffset; } public TCP setDataOffset(byte offset) { this.dataOffset = offset; return this; } public short getFlags() { return this.flags; } public TCP setFlags(short flags) { this.flags = flags; return this; } public short getWindowSize() { return this.windowSize; } public TCP setWindowSize(short windowSize) { this.windowSize = windowSize; return this; } public short getTcpChecksum() { return this.checksum; } public TCP setTcpChecksum(short checksum) { this.checksum = checksum; return this; } @Override public void resetChecksum() { this.checksum = 0; super.resetChecksum(); } public short getUrgentPointer(short urgentPointer) { return this.urgentPointer; } public TCP setUrgentPointer(short urgentPointer) { this.urgentPointer= urgentPointer; return this; } public byte[] getOptions() { return this.options; } public TCP setOptions(byte[] options) { this.options = options; this.dataOffset = (byte) ((20 + options.length + 3) >> 2); return this; } /** * @param checksum the checksum to set */ public TCP setChecksum(short checksum) { this.checksum = checksum; return this; } /** * Serializes the packet. Will compute and set the following fields if they * are set to specific values at the time serialize is called: * -checksum : 0 * -length : 0 */ public byte[] serialize() { int length; if (dataOffset == 0) dataOffset = 5; // default header length length = dataOffset << 2; byte[] payloadData = null; if (payload != null) { payload.setParent(this); payloadData = payload.serialize(); length += payloadData.length; } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putShort(this.sourcePort); bb.putShort(this.destinationPort); bb.putInt(this.sequence); bb.putInt(this.acknowledge); bb.putShort((short) (this.flags | (dataOffset << 12))); bb.putShort(this.windowSize); bb.putShort(this.checksum); bb.putShort(this.urgentPointer); if (dataOffset > 5) { int padding; bb.put(options); padding = (dataOffset << 2) - 20 - options.length; for (int i = 0; i < padding; i++) bb.put((byte) 0); } if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_TCP); // compute checksum if needed if (this.checksum == 0) { bb.rewind(); int accumulation = 0; // compute pseudo header mac if (this.parent != null && this.parent instanceof IPv4) { IPv4 ipv4 = (IPv4) this.parent; accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff) + (ipv4.getSourceAddress() & 0xffff); accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff) + (ipv4.getDestinationAddress() & 0xffff); accumulation += ipv4.getProtocol() & 0xff; accumulation += length & 0xffff; } for (int i = 0; i < length / 2; ++i) { accumulation += 0xffff & bb.getShort(); } // pad to an even number of shorts if (length % 2 > 0) { accumulation += (bb.get() & 0xff) << 8; } accumulation = ((accumulation >> 16) & 0xffff) + (accumulation & 0xffff); this.checksum = (short) (~accumulation & 0xffff); bb.putShort(16, this.checksum); } return data; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 5807; int result = super.hashCode(); result = prime * result + checksum; result = prime * result + destinationPort; result = prime * result + sourcePort; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof TCP)) return false; TCP other = (TCP) obj; // May want to compare fields based on the flags set return (checksum == other.checksum) && (destinationPort == other.destinationPort) && (sourcePort == other.sourcePort) && (sequence == other.sequence) && (acknowledge == other.acknowledge) && (dataOffset == other.dataOffset) && (flags == other.flags) && (windowSize == other.windowSize) && (urgentPointer == other.urgentPointer) && (dataOffset == 5 || options.equals(other.options)); } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); this.sourcePort = bb.getShort(); this.destinationPort = bb.getShort(); this.sequence = bb.getInt(); this.acknowledge = bb.getInt(); this.flags = bb.getShort(); this.dataOffset = (byte) ((this.flags >> 12) & 0xf); this.flags = (short) (this.flags & 0x1ff); this.windowSize = bb.getShort(); this.checksum = bb.getShort(); this.urgentPointer = bb.getShort(); if (this.dataOffset > 5) { int optLength = (dataOffset << 2) - 20; if (bb.limit() < bb.position()+optLength) { optLength = bb.limit() - bb.position(); } try { this.options = new byte[optLength]; bb.get(this.options, 0, optLength); } catch (IndexOutOfBoundsException e) { this.options = null; } } this.payload = new Data(); this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position()); this.payload.setParent(this); return this; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/BSN.java0000664000175000017500000001132612041336206026466 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; /** * @author Shudong Zhou (shudong.zhou@bigswitch.com) * */ public class BSN extends BasePacket { public static final int BSN_MAGIC = 0x20000604; public static final short BSN_VERSION_CURRENT = 0x0; public static final short BSN_TYPE_PROBE = 0x1; public static final short BSN_TYPE_BDDP = 0x2; public static Map> typeClassMap; static { typeClassMap = new HashMap>(); typeClassMap.put(BSN_TYPE_PROBE, BSNPROBE.class); typeClassMap.put(BSN_TYPE_BDDP, LLDP.class); } protected short type; protected short version; public BSN() { version = BSN_VERSION_CURRENT; } public BSN(short type) { this.type = type; version = BSN_VERSION_CURRENT; } public short getType() { return type; } public BSN setType(short type) { this.type = type; return this; } public short getVersion() { return version; } public BSN setVersion(short version) { this.version = version; return this; } @Override public byte[] serialize() { short length = 4 /* magic */ + 2 /* type */ + 2 /* version */; byte[] payloadData = null; if (this.payload != null) { payload.setParent(this); payloadData = payload.serialize(); length += payloadData.length; } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putInt(BSN_MAGIC); bb.putShort(this.type); bb.putShort(this.version); if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof Ethernet) ((Ethernet)this.parent).setEtherType(Ethernet.TYPE_BSN); return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); int magic = bb.getInt(); if (magic != BSN_MAGIC) { throw new RuntimeException("Invalid BSN magic " + magic); } this.type = bb.getShort(); this.version = bb.getShort(); if (this.version != BSN_VERSION_CURRENT) { throw new RuntimeException( "Invalid BSN packet version " + this.version + ", should be " + BSN_VERSION_CURRENT); } IPacket payload; if (typeClassMap.containsKey(this.type)) { Class clazz = typeClassMap.get(this.type); try { payload = clazz.newInstance(); } catch (Exception e) { throw new RuntimeException("Error parsing payload for BSN packet" + e); } } else { payload = new Data(); } this.payload = new Data(); this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position()); this.payload.setParent(this); return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 883; int result = super.hashCode(); result = prime * result + version; result = prime * result + type; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof BSN)) return false; BSN other = (BSN) obj; return (type == other.type && version == other.version); } public String toString() { StringBuffer sb = new StringBuffer("\n"); sb.append("BSN packet"); if (typeClassMap.containsKey(this.type)) sb.append(" type: " + typeClassMap.get(this.type).getCanonicalName()); else sb.append(" type: " + this.type); return sb.toString(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/ICMP.java0000664000175000017500000001105412041336206026572 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; /** * Implements ICMP packet format * @author shudong.zhou@bigswitch.com */ public class ICMP extends BasePacket { protected byte icmpType; protected byte icmpCode; protected short checksum; /** * @return the icmpType */ public byte getIcmpType() { return icmpType; } /** * @param icmpType to set */ public ICMP setIcmpType(byte icmpType) { this.icmpType = icmpType; return this; } /** * @return the icmp code */ public byte getIcmpCode() { return icmpCode; } /** * @param icmpCode code to set */ public ICMP setIcmpCode(byte icmpCode) { this.icmpCode = icmpCode; return this; } /** * @return the checksum */ public short getChecksum() { return checksum; } /** * @param checksum the checksum to set */ public ICMP setChecksum(short checksum) { this.checksum = checksum; return this; } /** * Serializes the packet. Will compute and set the following fields if they * are set to specific values at the time serialize is called: * -checksum : 0 * -length : 0 */ public byte[] serialize() { int length = 4; byte[] payloadData = null; if (payload != null) { payload.setParent(this); payloadData = payload.serialize(); length += payloadData.length; } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put(this.icmpType); bb.put(this.icmpCode); bb.putShort(this.checksum); if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_ICMP); // compute checksum if needed if (this.checksum == 0) { bb.rewind(); int accumulation = 0; for (int i = 0; i < length / 2; ++i) { accumulation += 0xffff & bb.getShort(); } // pad to an even number of shorts if (length % 2 > 0) { accumulation += (bb.get() & 0xff) << 8; } accumulation = ((accumulation >> 16) & 0xffff) + (accumulation & 0xffff); this.checksum = (short) (~accumulation & 0xffff); bb.putShort(2, this.checksum); } return data; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 5807; int result = super.hashCode(); result = prime * result + icmpType; result = prime * result + icmpCode; result = prime * result + checksum; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof ICMP)) return false; ICMP other = (ICMP) obj; if (icmpType != other.icmpType) return false; if (icmpCode != other.icmpCode) return false; if (checksum != other.checksum) return false; return true; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); this.icmpType = bb.get(); this.icmpCode = bb.get(); this.checksum = bb.getShort(); this.payload = new Data(); this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position()); this.payload.setParent(this); return this; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/LLC.java0000664000175000017500000000351012041336206026452 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; /** * This class represents an Link Local Control * header that is used in Ethernet 802.3. * @author alexreimers * */ public class LLC extends BasePacket { private byte dsap = 0; private byte ssap = 0; private byte ctrl = 0; public byte getDsap() { return dsap; } public void setDsap(byte dsap) { this.dsap = dsap; } public byte getSsap() { return ssap; } public void setSsap(byte ssap) { this.ssap = ssap; } public byte getCtrl() { return ctrl; } public void setCtrl(byte ctrl) { this.ctrl = ctrl; } @Override public byte[] serialize() { byte[] data = new byte[3]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put(dsap); bb.put(ssap); bb.put(ctrl); return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); dsap = bb.get(); ssap = bb.get(); ctrl = bb.get(); return this; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/LLDP.java0000664000175000017500000001302712041336206026577 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class LLDP extends BasePacket { protected LLDPTLV chassisId; protected LLDPTLV portId; protected LLDPTLV ttl; protected List optionalTLVList; protected short ethType; public LLDP() { this.optionalTLVList = new ArrayList(); this.ethType = Ethernet.TYPE_LLDP; } /** * @return the chassisId */ public LLDPTLV getChassisId() { return chassisId; } /** * @param chassisId the chassisId to set */ public LLDP setChassisId(LLDPTLV chassisId) { this.chassisId = chassisId; return this; } /** * @return the portId */ public LLDPTLV getPortId() { return portId; } /** * @param portId the portId to set */ public LLDP setPortId(LLDPTLV portId) { this.portId = portId; return this; } /** * @return the ttl */ public LLDPTLV getTtl() { return ttl; } /** * @param ttl the ttl to set */ public LLDP setTtl(LLDPTLV ttl) { this.ttl = ttl; return this; } /** * @return the optionalTLVList */ public List getOptionalTLVList() { return optionalTLVList; } /** * @param optionalTLVList the optionalTLVList to set */ public LLDP setOptionalTLVList(List optionalTLVList) { this.optionalTLVList = optionalTLVList; return this; } @Override public byte[] serialize() { int length = 2+this.chassisId.getLength() + 2+this.portId.getLength() + 2+this.ttl.getLength() + 2; for (LLDPTLV tlv : this.optionalTLVList) { length += 2 + tlv.getLength(); } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put(this.chassisId.serialize()); bb.put(this.portId.serialize()); bb.put(this.ttl.serialize()); for (LLDPTLV tlv : this.optionalTLVList) { bb.put(tlv.serialize()); } bb.putShort((short) 0); // End of LLDPDU if (this.parent != null && this.parent instanceof Ethernet) ((Ethernet)this.parent).setEtherType(ethType); return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); LLDPTLV tlv; do { tlv = new LLDPTLV().deserialize(bb); // if there was a failure to deserialize stop processing TLVs if (tlv == null) break; switch (tlv.getType()) { case 0x0: // can throw this one away, its just an end delimiter break; case 0x1: this.chassisId = tlv; break; case 0x2: this.portId = tlv; break; case 0x3: this.ttl = tlv; break; default: this.optionalTLVList.add(tlv); break; } } while (tlv.getType() != 0 && bb.hasRemaining()); return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 883; int result = super.hashCode(); result = prime * result + ((chassisId == null) ? 0 : chassisId.hashCode()); result = prime * result + (optionalTLVList.hashCode()); result = prime * result + ((portId == null) ? 0 : portId.hashCode()); result = prime * result + ((ttl == null) ? 0 : ttl.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof LLDP)) return false; LLDP other = (LLDP) obj; if (chassisId == null) { if (other.chassisId != null) return false; } else if (!chassisId.equals(other.chassisId)) return false; if (!optionalTLVList.equals(other.optionalTLVList)) return false; if (portId == null) { if (other.portId != null) return false; } else if (!portId.equals(other.portId)) return false; if (ttl == null) { if (other.ttl != null) return false; } else if (!ttl.equals(other.ttl)) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/DHCP.java0000664000175000017500000003530512041336206026565 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class DHCP extends BasePacket { /** * ------------------------------------------ * |op (1) | htype(1) | hlen(1) | hops(1) | * ------------------------------------------ * | xid (4) | * ------------------------------------------ * | secs (2) | flags (2) | * ------------------------------------------ * | ciaddr (4) | * ------------------------------------------ * | yiaddr (4) | * ------------------------------------------ * | siaddr (4) | * ------------------------------------------ * | giaddr (4) | * ------------------------------------------ * | chaddr (16) | * ------------------------------------------ * | sname (64) | * ------------------------------------------ * | file (128) | * ------------------------------------------ * | options (312) | * ------------------------------------------ * */ // Header + magic without options public static int MIN_HEADER_LENGTH = 240; public static byte OPCODE_REQUEST = 0x1; public static byte OPCODE_REPLY = 0x2; public static byte HWTYPE_ETHERNET = 0x1; public enum DHCPOptionCode { OptionCode_SubnetMask ((byte)1), OptionCode_RequestedIP ((byte)50), OptionCode_LeaseTime ((byte)51), OptionCode_MessageType ((byte)53), OptionCode_DHCPServerIp ((byte)54), OptionCode_RequestedParameters ((byte)55), OptionCode_RenewalTime ((byte)58), OPtionCode_RebindingTime ((byte)59), OptionCode_ClientID ((byte)61), OptionCode_END ((byte)255); protected byte value; private DHCPOptionCode(byte value) { this.value = value; } public byte getValue() { return value; } } protected byte opCode; protected byte hardwareType; protected byte hardwareAddressLength; protected byte hops; protected int transactionId; protected short seconds; protected short flags; protected int clientIPAddress; protected int yourIPAddress; protected int serverIPAddress; protected int gatewayIPAddress; protected byte[] clientHardwareAddress; protected String serverName; protected String bootFileName; protected List options = new ArrayList(); /** * @return the opCode */ public byte getOpCode() { return opCode; } /** * @param opCode the opCode to set */ public DHCP setOpCode(byte opCode) { this.opCode = opCode; return this; } /** * @return the hardwareType */ public byte getHardwareType() { return hardwareType; } /** * @param hardwareType the hardwareType to set */ public DHCP setHardwareType(byte hardwareType) { this.hardwareType = hardwareType; return this; } /** * @return the hardwareAddressLength */ public byte getHardwareAddressLength() { return hardwareAddressLength; } /** * @param hardwareAddressLength the hardwareAddressLength to set */ public DHCP setHardwareAddressLength(byte hardwareAddressLength) { this.hardwareAddressLength = hardwareAddressLength; return this; } /** * @return the hops */ public byte getHops() { return hops; } /** * @param hops the hops to set */ public DHCP setHops(byte hops) { this.hops = hops; return this; } /** * @return the transactionId */ public int getTransactionId() { return transactionId; } /** * @param transactionId the transactionId to set */ public DHCP setTransactionId(int transactionId) { this.transactionId = transactionId; return this; } /** * @return the seconds */ public short getSeconds() { return seconds; } /** * @param seconds the seconds to set */ public DHCP setSeconds(short seconds) { this.seconds = seconds; return this; } /** * @return the flags */ public short getFlags() { return flags; } /** * @param flags the flags to set */ public DHCP setFlags(short flags) { this.flags = flags; return this; } /** * @return the clientIPAddress */ public int getClientIPAddress() { return clientIPAddress; } /** * @param clientIPAddress the clientIPAddress to set */ public DHCP setClientIPAddress(int clientIPAddress) { this.clientIPAddress = clientIPAddress; return this; } /** * @return the yourIPAddress */ public int getYourIPAddress() { return yourIPAddress; } /** * @param yourIPAddress the yourIPAddress to set */ public DHCP setYourIPAddress(int yourIPAddress) { this.yourIPAddress = yourIPAddress; return this; } /** * @return the serverIPAddress */ public int getServerIPAddress() { return serverIPAddress; } /** * @param serverIPAddress the serverIPAddress to set */ public DHCP setServerIPAddress(int serverIPAddress) { this.serverIPAddress = serverIPAddress; return this; } /** * @return the gatewayIPAddress */ public int getGatewayIPAddress() { return gatewayIPAddress; } /** * @param gatewayIPAddress the gatewayIPAddress to set */ public DHCP setGatewayIPAddress(int gatewayIPAddress) { this.gatewayIPAddress = gatewayIPAddress; return this; } /** * @return the clientHardwareAddress */ public byte[] getClientHardwareAddress() { return clientHardwareAddress; } /** * @param clientHardwareAddress the clientHardwareAddress to set */ public DHCP setClientHardwareAddress(byte[] clientHardwareAddress) { this.clientHardwareAddress = clientHardwareAddress; return this; } /** * Gets a specific DHCP option parameter * @param opetionCode The option code to get * @return The value of the option if it exists, null otherwise */ public DHCPOption getOption(DHCPOptionCode optionCode) { for (DHCPOption opt : options) { if (opt.code == optionCode.value) return opt; } return null; } /** * @return the options */ public List getOptions() { return options; } /** * @param options the options to set */ public DHCP setOptions(List options) { this.options = options; return this; } /** * @return the packetType base on option 53 */ public DHCPPacketType getPacketType() { ListIterator lit = options.listIterator(); while (lit.hasNext()) { DHCPOption option = lit.next(); // only care option 53 if (option.getCode() == 53) { return DHCPPacketType.getType(option.getData()[0]); } } return null; } /** * @return the serverName */ public String getServerName() { return serverName; } /** * @param serverName the serverName to set */ public DHCP setServerName(String serverName) { this.serverName = serverName; return this; } /** * @return the bootFileName */ public String getBootFileName() { return bootFileName; } /** * @param bootFileName the bootFileName to set */ public DHCP setBootFileName(String bootFileName) { this.bootFileName = bootFileName; return this; } @Override public byte[] serialize() { // not guaranteed to retain length/exact format resetChecksum(); // minimum size 240 including magic cookie, options generally padded to 300 int optionsLength = 0; for (DHCPOption option : this.options) { if (option.getCode() == 0 || option.getCode() == 255) { optionsLength += 1; } else { optionsLength += 2 + (int)(0xff & option.getLength()); } } int optionsPadLength = 0; if (optionsLength < 60) optionsPadLength = 60 - optionsLength; byte[] data = new byte[240+optionsLength+optionsPadLength]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put(this.opCode); bb.put(this.hardwareType); bb.put(this.hardwareAddressLength); bb.put(this.hops); bb.putInt(this.transactionId); bb.putShort(this.seconds); bb.putShort(this.flags); bb.putInt(this.clientIPAddress); bb.putInt(this.yourIPAddress); bb.putInt(this.serverIPAddress); bb.putInt(this.gatewayIPAddress); bb.put(this.clientHardwareAddress); if (this.clientHardwareAddress.length < 16) { for (int i = 0; i < (16 - this.clientHardwareAddress.length); ++i) { bb.put((byte) 0x0); } } writeString(this.serverName, bb, 64); writeString(this.bootFileName, bb, 128); // magic cookie bb.put((byte) 0x63); bb.put((byte) 0x82); bb.put((byte) 0x53); bb.put((byte) 0x63); for (DHCPOption option : this.options) { int code = option.getCode() & 0xff; bb.put((byte) code); if ((code != 0) && (code != 255)) { bb.put(option.getLength()); bb.put(option.getData()); } } // assume the rest is padded out with zeroes return data; } protected void writeString(String string, ByteBuffer bb, int maxLength) { if (string == null) { for (int i = 0; i < maxLength; ++i) { bb.put((byte) 0x0); } } else { byte[] bytes = null; try { bytes = string.getBytes("ascii"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Failure encoding server name", e); } int writeLength = bytes.length; if (writeLength > maxLength) { writeLength = maxLength; } bb.put(bytes, 0, writeLength); for (int i = writeLength; i < maxLength; ++i) { bb.put((byte) 0x0); } } } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); if (bb.remaining() < MIN_HEADER_LENGTH) { return this; } this.opCode = bb.get(); this.hardwareType = bb.get(); this.hardwareAddressLength = bb.get(); this.hops = bb.get(); this.transactionId = bb.getInt(); this.seconds = bb.getShort(); this.flags = bb.getShort(); this.clientIPAddress = bb.getInt(); this.yourIPAddress = bb.getInt(); this.serverIPAddress = bb.getInt(); this.gatewayIPAddress = bb.getInt(); int hardwareAddressLength = 0xff & this.hardwareAddressLength; this.clientHardwareAddress = new byte[hardwareAddressLength]; bb.get(this.clientHardwareAddress); for (int i = hardwareAddressLength; i < 16; ++i) bb.get(); this.serverName = readString(bb, 64); this.bootFileName = readString(bb, 128); // read the magic cookie // magic cookie bb.get(); bb.get(); bb.get(); bb.get(); // read options while (bb.hasRemaining()) { DHCPOption option = new DHCPOption(); int code = 0xff & bb.get(); // convert signed byte to int in range [0,255] option.setCode((byte) code); if (code == 0) { // skip these continue; } else if (code != 255) { if (bb.hasRemaining()) { int l = 0xff & bb.get(); // convert signed byte to int in range [0,255] option.setLength((byte) l); if (bb.remaining() >= l) { byte[] optionData = new byte[l]; bb.get(optionData); option.setData(optionData); } else { // Skip the invalid option and set the END option code = 0xff; option.setCode((byte)code); option.setLength((byte) 0); } } else { // Skip the invalid option and set the END option code = 0xff; option.setCode((byte)code); option.setLength((byte) 0); } } this.options.add(option); if (code == 255) { // remaining bytes are supposed to be 0, but ignore them just in case break; } } return this; } protected String readString(ByteBuffer bb, int maxLength) { byte[] bytes = new byte[maxLength]; bb.get(bytes); String result = null; try { result = new String(bytes, "ascii").trim(); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Failure decoding string", e); } return result; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/BPDU.java0000664000175000017500000001014112041336206026570 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; /** * This class is a Rapid Spanning Tree Protocol * Bridge Protocol Data Unit * @author alexreimers */ public class BPDU extends BasePacket { public enum BPDUType { CONFIG, TOPOLOGY_CHANGE; } private final long destMac = 0x0180c2000000L; // 01-80-c2-00-00-00 // TODO - check this for RSTP private LLC llcHeader; private short protocolId = 0; private byte version = 0; private byte type; private byte flags; private byte[] rootBridgeId; private int rootPathCost; private byte[] senderBridgeId; // switch cluster MAC private short portId; // port it was transmitted from private short messageAge; // 256ths of a second private short maxAge; // 256ths of a second private short helloTime; // 256ths of a second private short forwardDelay; // 256ths of a second public BPDU(BPDUType type) { rootBridgeId = new byte[8]; senderBridgeId = new byte[8]; llcHeader = new LLC(); llcHeader.setDsap((byte) 0x42); llcHeader.setSsap((byte) 0x42); llcHeader.setCtrl((byte) 0x03); switch(type) { case CONFIG: this.type = 0x0; break; case TOPOLOGY_CHANGE: this.type = (byte) 0x80; // 1000 0000 break; default: this.type = 0; break; } } @Override public byte[] serialize() { byte[] data; // TODO check these if (type == 0x0) { // config data = new byte[38]; } else { // topology change data = new byte[7]; // LLC + TC notification } ByteBuffer bb = ByteBuffer.wrap(data); // Serialize the LLC header byte[] llc = llcHeader.serialize(); bb.put(llc, 0, llc.length); bb.putShort(protocolId); bb.put(version); bb.put(type); if (type == 0x0) { bb.put(flags); bb.put(rootBridgeId, 0, rootBridgeId.length); bb.putInt(rootPathCost); bb.put(senderBridgeId, 0, senderBridgeId.length); bb.putShort(portId); bb.putShort(messageAge); bb.putShort(maxAge); bb.putShort(helloTime); bb.putShort(forwardDelay); } return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); // LLC header llcHeader.deserialize(data, offset, 3); this.protocolId = bb.getShort(); this.version = bb.get(); this.type = bb.get(); // These fields only exist if it's a configuration BPDU if (this.type == 0x0) { this.flags = bb.get(); bb.get(rootBridgeId, 0, 6); this.rootPathCost = bb.getInt(); bb.get(this.senderBridgeId, 0, 6); this.portId = bb.getShort(); this.messageAge = bb.getShort(); this.maxAge = bb.getShort(); this.helloTime = bb.getShort(); this.forwardDelay = bb.getShort(); } // TODO should we set other fields to 0? return this; } public long getDestMac() { return destMac; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/Ethernet.java0000664000175000017500000003451412041336206027626 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.util.MACAddress; import org.openflow.util.HexString; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class Ethernet extends BasePacket { private static String HEXES = "0123456789ABCDEF"; public static final short TYPE_ARP = 0x0806; public static final short TYPE_RARP = (short) 0x8035; public static final short TYPE_IPv4 = 0x0800; public static final short TYPE_LLDP = (short) 0x88cc; public static final short TYPE_BSN = (short) 0x8942; public static final short VLAN_UNTAGGED = (short)0xffff; public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes public static Map> etherTypeClassMap; static { etherTypeClassMap = new HashMap>(); etherTypeClassMap.put(TYPE_ARP, ARP.class); etherTypeClassMap.put(TYPE_RARP, ARP.class); etherTypeClassMap.put(TYPE_IPv4, IPv4.class); etherTypeClassMap.put(TYPE_LLDP, LLDP.class); etherTypeClassMap.put(TYPE_BSN, BSN.class); } protected MACAddress destinationMACAddress; protected MACAddress sourceMACAddress; protected byte priorityCode; protected short vlanID; protected short etherType; protected boolean pad = false; /** * By default, set Ethernet to untagged */ public Ethernet() { super(); this.vlanID = VLAN_UNTAGGED; } /** * @return the destination MAC as a byte array */ public byte[] getDestinationMACAddress() { return destinationMACAddress.toBytes(); } /** * @return the destination MAC */ public MACAddress getDestinationMAC() { return destinationMACAddress; } /** * @param destinationMACAddress the destination MAC to set */ public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) { this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress); return this; } /** * @param destinationMACAddress the destination MAC to set */ public Ethernet setDestinationMACAddress(String destinationMACAddress) { this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress); return this; } /** * @return the source MACAddress as a byte array */ public byte[] getSourceMACAddress() { return sourceMACAddress.toBytes(); } /** * @return the source MACAddress */ public MACAddress getSourceMAC() { return sourceMACAddress; } /** * @param sourceMACAddress the source MAC to set */ public Ethernet setSourceMACAddress(byte[] sourceMACAddress) { this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress); return this; } /** * @param sourceMACAddress the source MAC to set */ public Ethernet setSourceMACAddress(String sourceMACAddress) { this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress); return this; } /** * @return the priorityCode */ public byte getPriorityCode() { return priorityCode; } /** * @param priorityCode the priorityCode to set */ public Ethernet setPriorityCode(byte priorityCode) { this.priorityCode = priorityCode; return this; } /** * @return the vlanID */ public short getVlanID() { return vlanID; } /** * @param vlanID the vlanID to set */ public Ethernet setVlanID(short vlanID) { this.vlanID = vlanID; return this; } /** * @return the etherType */ public short getEtherType() { return etherType; } /** * @param etherType the etherType to set */ public Ethernet setEtherType(short etherType) { this.etherType = etherType; return this; } /** * @return True if the Ethernet frame is broadcast, false otherwise */ public boolean isBroadcast() { assert(destinationMACAddress.length() == 6); return destinationMACAddress.isBroadcast(); } /** * @return True is the Ethernet frame is multicast, False otherwise */ public boolean isMulticast() { return destinationMACAddress.isMulticast(); } /** * Pad this packet to 60 bytes minimum, filling with zeros? * @return the pad */ public boolean isPad() { return pad; } /** * Pad this packet to 60 bytes minimum, filling with zeros? * @param pad the pad to set */ public Ethernet setPad(boolean pad) { this.pad = pad; return this; } public byte[] serialize() { byte[] payloadData = null; if (payload != null) { payload.setParent(this); payloadData = payload.serialize(); } int length = 14 + ((vlanID == VLAN_UNTAGGED) ? 0 : 4) + ((payloadData == null) ? 0 : payloadData.length); if (pad && length < 60) { length = 60; } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.put(destinationMACAddress.toBytes()); bb.put(sourceMACAddress.toBytes()); if (vlanID != VLAN_UNTAGGED) { bb.putShort((short) 0x8100); bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff))); } bb.putShort(etherType); if (payloadData != null) bb.put(payloadData); if (pad) { Arrays.fill(data, bb.position(), data.length, (byte)0x0); } return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { if (length <= 0) return null; ByteBuffer bb = ByteBuffer.wrap(data, offset, length); if (this.destinationMACAddress == null) this.destinationMACAddress = MACAddress.valueOf(new byte[6]); byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH]; bb.get(dstAddr); this.destinationMACAddress = MACAddress.valueOf(dstAddr); if (this.sourceMACAddress == null) this.sourceMACAddress = MACAddress.valueOf(new byte[6]); byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH]; bb.get(srcAddr); this.sourceMACAddress = MACAddress.valueOf(srcAddr); short etherType = bb.getShort(); if (etherType == (short) 0x8100) { short tci = bb.getShort(); this.priorityCode = (byte) ((tci >> 13) & 0x07); this.vlanID = (short) (tci & 0x0fff); etherType = bb.getShort(); } else { this.vlanID = VLAN_UNTAGGED; } this.etherType = etherType; IPacket payload; if (Ethernet.etherTypeClassMap.containsKey(this.etherType)) { Class clazz = Ethernet.etherTypeClassMap.get(this.etherType); try { payload = clazz.newInstance(); } catch (Exception e) { throw new RuntimeException("Error parsing payload for Ethernet packet", e); } } else { payload = new Data(); } this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position()); this.payload.setParent(this); return this; } /** * Checks to see if a string is a valid MAC address. * @param macAddress * @return True if macAddress is a valid MAC, False otherwise */ public static boolean isMACAddress(String macAddress) { String[] macBytes = macAddress.split(":"); if (macBytes.length != 6) return false; for (int i = 0; i < 6; ++i) { if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 || HEXES.indexOf(macBytes[i].toUpperCase().charAt(1)) == -1) { return false; } } return true; } /** * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not * matter, and returns a corresponding byte[]. * @param macAddress The MAC address to convert into a bye array * @return The macAddress as a byte array */ public static byte[] toMACAddress(String macAddress) { return MACAddress.valueOf(macAddress).toBytes(); } /** * Accepts a MAC address and returns the corresponding long, where the * MAC bytes are set on the lower order bytes of the long. * @param macAddress * @return a long containing the mac address bytes */ public static long toLong(byte[] macAddress) { return MACAddress.valueOf(macAddress).toLong(); } /** * Convert a long MAC address to a byte array * @param macAddress * @return the bytes of the mac address */ public static byte[] toByteArray(long macAddress) { return MACAddress.valueOf(macAddress).toBytes(); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 7867; int result = super.hashCode(); result = prime * result + destinationMACAddress.hashCode(); result = prime * result + etherType; result = prime * result + vlanID; result = prime * result + priorityCode; result = prime * result + (pad ? 1231 : 1237); result = prime * result + sourceMACAddress.hashCode(); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof Ethernet)) return false; Ethernet other = (Ethernet) obj; if (!destinationMACAddress.equals(other.destinationMACAddress)) return false; if (priorityCode != other.priorityCode) return false; if (vlanID != other.vlanID) return false; if (etherType != other.etherType) return false; if (pad != other.pad) return false; if (!sourceMACAddress.equals(other.sourceMACAddress)) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString(java.lang.Object) */ @Override public String toString() { StringBuffer sb = new StringBuffer("\n"); IPacket pkt = (IPacket) this.getPayload(); if (pkt instanceof ARP) sb.append("arp"); else if (pkt instanceof LLDP) sb.append("lldp"); else if (pkt instanceof ICMP) sb.append("icmp"); else if (pkt instanceof IPv4) sb.append("ip"); else if (pkt instanceof DHCP) sb.append("dhcp"); else sb.append(this.getEtherType()); sb.append("\ndl_vlan: "); if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) sb.append("untagged"); else sb.append(this.getVlanID()); sb.append("\ndl_vlan_pcp: "); sb.append(this.getPriorityCode()); sb.append("\ndl_src: "); sb.append(HexString.toHexString(this.getSourceMACAddress())); sb.append("\ndl_dst: "); sb.append(HexString.toHexString(this.getDestinationMACAddress())); if (pkt instanceof ARP) { ARP p = (ARP) pkt; sb.append("\nnw_src: "); sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getSenderProtocolAddress()))); sb.append("\nnw_dst: "); sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getTargetProtocolAddress()))); } else if (pkt instanceof LLDP) { sb.append("lldp packet"); } else if (pkt instanceof ICMP) { ICMP icmp = (ICMP) pkt; sb.append("\nicmp_type: "); sb.append(icmp.getIcmpType()); sb.append("\nicmp_code: "); sb.append(icmp.getIcmpCode()); } else if (pkt instanceof IPv4) { IPv4 p = (IPv4) pkt; sb.append("\nnw_src: "); sb.append(IPv4.fromIPv4Address(p.getSourceAddress())); sb.append("\nnw_dst: "); sb.append(IPv4.fromIPv4Address(p.getDestinationAddress())); sb.append("\nnw_tos: "); sb.append(p.getDiffServ()); sb.append("\nnw_proto: "); sb.append(p.getProtocol()); if (pkt instanceof TCP) { sb.append("\ntp_src: "); sb.append(((TCP) pkt).getSourcePort()); sb.append("\ntp_dst: "); sb.append(((TCP) pkt).getDestinationPort()); } else if (pkt instanceof UDP) { sb.append("\ntp_src: "); sb.append(((UDP) pkt).getSourcePort()); sb.append("\ntp_dst: "); sb.append(((UDP) pkt).getDestinationPort()); } if (pkt instanceof ICMP) { ICMP icmp = (ICMP) pkt; sb.append("\nicmp_type: "); sb.append(icmp.getIcmpType()); sb.append("\nicmp_code: "); sb.append(icmp.getIcmpCode()); } } else if (pkt instanceof DHCP) { sb.append("\ndhcp packet"); } else if (pkt instanceof Data) { sb.append("\ndata packet"); } else if (pkt instanceof LLC) { sb.append("\nllc packet"); } else if (pkt instanceof BPDU) { sb.append("\nbpdu packet"); } else sb.append("\nunknwon packet"); return sb.toString(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/DHCPOption.java0000664000175000017500000000543312041336206027755 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.util.Arrays; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class DHCPOption { protected byte code; protected byte length; protected byte[] data; /** * @return the code */ public byte getCode() { return code; } /** * @param code the code to set */ public DHCPOption setCode(byte code) { this.code = code; return this; } /** * @return the length */ public byte getLength() { return length; } /** * @param length the length to set */ public DHCPOption setLength(byte length) { this.length = length; return this; } /** * @return the data */ public byte[] getData() { return data; } /** * @param data the data to set */ public DHCPOption setData(byte[] data) { this.data = data; return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + code; result = prime * result + Arrays.hashCode(data); result = prime * result + length; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof DHCPOption)) return false; DHCPOption other = (DHCPOption) obj; if (code != other.code) return false; if (!Arrays.equals(data, other.data)) return false; if (length != other.length) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "DHCPOption [code=" + code + ", length=" + length + ", data=" + Arrays.toString(data) + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java0000664000175000017500000001213112041336206027251 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; import org.openflow.util.HexString; /** * @author Shudong Zhou (shudong.zhou@bigswitch.com) * */ public class BSNPROBE extends BasePacket { protected long controllerId; protected int sequenceId; protected byte[] srcMac; protected byte[] dstMac; protected long srcSwDpid; protected int srcPortNo; public BSNPROBE() { srcMac = new byte[6]; dstMac = new byte[6]; } public long getControllerId() { return this.controllerId; } public BSNPROBE setControllerId(long controllerId) { this.controllerId = controllerId; return this; } public int getSequenceId() { return sequenceId; } public BSNPROBE setSequenceId(int sequenceId) { this.sequenceId = sequenceId; return this; } public byte[] getSrcMac() { return this.srcMac; } public BSNPROBE setSrcMac(byte[] srcMac) { this.srcMac = srcMac; return this; } public byte[] getDstMac() { return dstMac; } public BSNPROBE setDstMac(byte[] dstMac) { this.dstMac = dstMac; return this; } public long getSrcSwDpid() { return srcSwDpid; } public BSNPROBE setSrcSwDpid(long srcSwDpid) { this.srcSwDpid = srcSwDpid; return this; } public int getSrcPortNo() { return srcPortNo; } public BSNPROBE setSrcPortNo(int srcPortNo) { this.srcPortNo = srcPortNo; return this; } @Override public byte[] serialize() { short length = 8 /* controllerId */ + 4 /* seqId */ + 12 /* srcMac dstMac */ + 8 /* srcSwDpid */ + 4 /* srcPortNo */; byte[] payloadData = null; if (this.payload != null) { payload.setParent(this); payloadData = payload.serialize(); length += payloadData.length; } byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putLong(this.controllerId); bb.putInt(this.sequenceId); bb.put(this.srcMac); bb.put(this.dstMac); bb.putLong(this.srcSwDpid); bb.putInt(this.srcPortNo); if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof BSN) ((BSN)this.parent).setType(BSN.BSN_TYPE_PROBE); return data; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); controllerId = bb.getLong(); sequenceId = bb.getInt(); bb.get(this.srcMac, 0, 6); bb.get(this.dstMac, 0, 6); this.srcSwDpid = bb.getLong(); this.srcPortNo = bb.getInt(); if (bb.hasRemaining()) { this.payload = new Data(); this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position()); this.payload.setParent(this); } return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 883; int result = super.hashCode(); result = prime * result + srcMac.hashCode(); result = prime * result + dstMac.hashCode(); result = prime * result + (int) (srcSwDpid >> 32) + (int) srcSwDpid; result = prime * result + srcPortNo; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof BSNPROBE)) return false; BSNPROBE other = (BSNPROBE) obj; if (!Arrays.equals(srcMac, other.srcMac)) return false; if (!Arrays.equals(dstMac, other.dstMac)) return false; return (sequenceId == other.sequenceId && srcSwDpid == other.srcSwDpid && srcPortNo == other.srcPortNo ); } public String toString() { StringBuffer sb = new StringBuffer("\n"); sb.append("BSN Probe packet"); sb.append("\nSource Mac: "); sb.append(HexString.toHexString(srcMac)); sb.append("\nDestination Mac: "); sb.append(HexString.toHexString(dstMac)); sb.append("\nSource Switch: "); sb.append(HexString.toHexString(srcSwDpid)); sb.append(" port: " + srcPortNo); sb.append("\nSequence No.:" + sequenceId); return sb.toString(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/LLDPOrganizationalTLV.java0000664000175000017500000001254612041336206032074 0ustar jamespagejamespage/** * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Arrays; /** * The class representing LLDP Organizationally Specific TLV. * * @author Sho Shimizu (sho.shimizu@gmail.com) */ public class LLDPOrganizationalTLV extends LLDPTLV { public static final int OUI_LENGTH = 3; public static final int SUBTYPE_LENGTH = 1; public static final byte ORGANIZATIONAL_TLV_TYPE = 127; public static final int MAX_INFOSTRING_LENGTH = 507; protected byte[] oui; protected byte subType; private byte[] infoString; public LLDPOrganizationalTLV() { type = ORGANIZATIONAL_TLV_TYPE; } /** * Set the value of OUI. * @param oui The value of OUI to be set. * @return This LLDP Organizationally Specific TLV. */ public LLDPOrganizationalTLV setOUI(byte[] oui) { if (oui.length != OUI_LENGTH) { throw new IllegalArgumentException("The length of OUI must be " + OUI_LENGTH + ", but it is " + oui.length); } this.oui = Arrays.copyOf(oui, oui.length); return this; } /** * Returns the value of the OUI. * @return The value of the OUI . */ public byte[] getOUI() { return Arrays.copyOf(oui, oui.length); } /** * Set the value of sub type. * @param subType The value of sub type to be set. * @return This LLDP Organizationally Specific TLV. */ public LLDPOrganizationalTLV setSubType(byte subType) { this.subType = subType; return this; } /** * Returns the value of the sub type. * @return The value of the sub type. */ public byte getSubType() { return subType; } /** * Set the value of information string. * @param infoString the byte array of the value of information string. * @return This LLDP Organizationally Specific TLV. */ public LLDPOrganizationalTLV setInfoString(byte[] infoString) { if (infoString.length > MAX_INFOSTRING_LENGTH) { throw new IllegalArgumentException("The length of infoString cannot exceed " + MAX_INFOSTRING_LENGTH); } this.infoString = Arrays.copyOf(infoString, infoString.length); return this; } /** * Set the value of information string. * The String value is automatically converted into byte array with UTF-8 encoding. * @param infoString the String value of information string. * @return This LLDP Organizationally Specific TLV. */ public LLDPOrganizationalTLV setInfoString(String infoString) { byte[] infoStringBytes = infoString.getBytes(Charset.forName("UTF-8")); return setInfoString(infoStringBytes); } /** * Returns the value of information string. * @return the value of information string. */ public byte[] getInfoString() { return Arrays.copyOf(infoString, infoString.length); } @Override public byte[] serialize() { int valueLength = OUI_LENGTH + SUBTYPE_LENGTH + infoString.length; value = new byte[valueLength]; ByteBuffer bb = ByteBuffer.wrap(value); bb.put(oui); bb.put(subType); bb.put(infoString); return super.serialize(); } @Override public LLDPTLV deserialize(ByteBuffer bb) { super.deserialize(bb); ByteBuffer optionalField = ByteBuffer.wrap(value); byte[] oui = new byte[OUI_LENGTH]; optionalField.get(oui); setOUI(oui); setSubType(optionalField.get()); byte[] infoString = new byte[getLength() - OUI_LENGTH - SUBTYPE_LENGTH]; optionalField.get(infoString); setInfoString(infoString); return this; } @Override public int hashCode() { final int prime = 1423; int result = 1; result = prime * result + type; result = prime * result + length; result = prime * result + Arrays.hashCode(oui); result = prime * result + subType; result = prime * result + Arrays.hashCode(infoString); return result; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof LLDPOrganizationalTLV)) { return false; } LLDPOrganizationalTLV other = (LLDPOrganizationalTLV)o; if (this.type != other.type) { return false; } if (this.length != other.length) { return false; } if (!Arrays.equals(this.oui, other.oui)) { return false; } if (this.subType != other.subType) { return false; } if (!Arrays.equals(this.infoString, other.infoString)) { return false; } return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/UDP.java0000664000175000017500000001561012041336206026474 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class UDP extends BasePacket { public static Map> decodeMap; public static short DHCP_SERVER_PORT = (short)67; public static short DHCP_CLIENT_PORT = (short)68; static { decodeMap = new HashMap>(); /* * Disable DHCP until the deserialize code is hardened to deal with garbage input */ UDP.decodeMap.put(DHCP_SERVER_PORT, DHCP.class); UDP.decodeMap.put(DHCP_CLIENT_PORT, DHCP.class); } protected short sourcePort; protected short destinationPort; protected short length; protected short checksum; /** * @return the sourcePort */ public short getSourcePort() { return sourcePort; } /** * @param sourcePort the sourcePort to set */ public UDP setSourcePort(short sourcePort) { this.sourcePort = sourcePort; return this; } /** * @return the destinationPort */ public short getDestinationPort() { return destinationPort; } /** * @param destinationPort the destinationPort to set */ public UDP setDestinationPort(short destinationPort) { this.destinationPort = destinationPort; return this; } /** * @return the length */ public short getLength() { return length; } /** * @return the checksum */ public short getChecksum() { return checksum; } /** * @param checksum the checksum to set */ public UDP setChecksum(short checksum) { this.checksum = checksum; return this; } @Override public void resetChecksum() { this.checksum = 0; super.resetChecksum(); } /** * Serializes the packet. Will compute and set the following fields if they * are set to specific values at the time serialize is called: * -checksum : 0 * -length : 0 */ public byte[] serialize() { byte[] payloadData = null; if (payload != null) { payload.setParent(this); payloadData = payload.serialize(); } this.length = (short) (8 + ((payloadData == null) ? 0 : payloadData.length)); byte[] data = new byte[this.length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putShort(this.sourcePort); bb.putShort(this.destinationPort); bb.putShort(this.length); bb.putShort(this.checksum); if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_UDP); // compute checksum if needed if (this.checksum == 0) { bb.rewind(); int accumulation = 0; // compute pseudo header mac if (this.parent != null && this.parent instanceof IPv4) { IPv4 ipv4 = (IPv4) this.parent; accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff) + (ipv4.getSourceAddress() & 0xffff); accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff) + (ipv4.getDestinationAddress() & 0xffff); accumulation += ipv4.getProtocol() & 0xff; accumulation += this.length & 0xffff; } for (int i = 0; i < this.length / 2; ++i) { accumulation += 0xffff & bb.getShort(); } // pad to an even number of shorts if (this.length % 2 > 0) { accumulation += (bb.get() & 0xff) << 8; } accumulation = ((accumulation >> 16) & 0xffff) + (accumulation & 0xffff); this.checksum = (short) (~accumulation & 0xffff); bb.putShort(6, this.checksum); } return data; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 5807; int result = super.hashCode(); result = prime * result + checksum; result = prime * result + destinationPort; result = prime * result + length; result = prime * result + sourcePort; return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (!(obj instanceof UDP)) return false; UDP other = (UDP) obj; if (checksum != other.checksum) return false; if (destinationPort != other.destinationPort) return false; if (length != other.length) return false; if (sourcePort != other.sourcePort) return false; return true; } @Override public IPacket deserialize(byte[] data, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); this.sourcePort = bb.getShort(); this.destinationPort = bb.getShort(); this.length = bb.getShort(); this.checksum = bb.getShort(); if (UDP.decodeMap.containsKey(this.destinationPort)) { try { this.payload = UDP.decodeMap.get(this.destinationPort).getConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("Failure instantiating class", e); } } else if (UDP.decodeMap.containsKey(this.sourcePort)) { try { this.payload = UDP.decodeMap.get(this.sourcePort).getConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("Failure instantiating class", e); } } else { this.payload = new Data(); } this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position()); this.payload.setParent(this); return this; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/LLDPTLV.java0000664000175000017500000000674312041336206027174 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; /** * * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class LLDPTLV { protected byte type; protected short length; protected byte[] value; /** * @return the type */ public byte getType() { return type; } /** * @param type the type to set */ public LLDPTLV setType(byte type) { this.type = type; return this; } /** * @return the length */ public short getLength() { return length; } /** * @param length the length to set */ public LLDPTLV setLength(short length) { this.length = length; return this; } /** * @return the value */ public byte[] getValue() { return value; } /** * @param value the value to set */ public LLDPTLV setValue(byte[] value) { this.value = value; return this; } public byte[] serialize() { // type = 7 bits // info string length 9 bits, each value == byte // info string short scratch = (short) (((0x7f & this.type) << 9) | (0x1ff & this.length)); byte[] data = new byte[2+this.length]; ByteBuffer bb = ByteBuffer.wrap(data); bb.putShort(scratch); if (this.value != null) bb.put(this.value); return data; } public LLDPTLV deserialize(ByteBuffer bb) { short sscratch; sscratch = bb.getShort(); this.type = (byte) ((sscratch >> 9) & 0x7f); this.length = (short) (sscratch & 0x1ff); if (this.length > 0) { this.value = new byte[this.length]; // if there is an underrun just toss the TLV if (bb.remaining() < this.length) return null; bb.get(this.value); } return this; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 1423; int result = 1; result = prime * result + length; result = prime * result + type; result = prime * result + Arrays.hashCode(value); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof LLDPTLV)) return false; LLDPTLV other = (LLDPTLV) obj; if (length != other.length) return false; if (type != other.type) return false; if (!Arrays.equals(value, other.value)) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/packet/DHCPPacketType.java0000664000175000017500000000613212041336206030553 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; public enum DHCPPacketType { // From RFC 1533 DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPDECLINE (4), DHCPACK (5), DHCPNAK (6), DHCPRELEASE (7), // From RFC2132 DHCPINFORM (8), // From RFC3203 DHCPFORCERENEW (9), // From RFC4388 DHCPLEASEQUERY (10), DHCPLEASEUNASSIGNED (11), DHCPLEASEUNKNOWN (12), DHCPLEASEACTIVE (13); protected int value; private DHCPPacketType(int value) { this.value = value; } public int getValue() { return value; } public String toString(){ switch (value) { case 1: return "DHCPDISCOVER"; case 2: return "DHCPOFFER"; case 3: return "DHCPREQUEST"; case 4: return "DHCPDECLINE"; case 5: return "DHCPACK"; case 6: return "DHCPNAK"; case 7: return "DHCPRELEASE"; case 8: return "DHCPINFORM"; case 9: return "DHCPFORCERENEW"; case 10: return "DHCPLEASEQUERY"; case 11: return "DHCPLEASEUNASSIGNED"; case 12: return "DHCPLEASEUNKNOWN"; case 13: return "DHCPLEASEACTIVE"; } return null; } public static DHCPPacketType getType(int value) { switch (value) { case 1: return DHCPDISCOVER; case 2: return DHCPOFFER; case 3: return DHCPREQUEST; case 4: return DHCPDECLINE; case 5: return DHCPACK; case 6: return DHCPNAK; case 7: return DHCPRELEASE; case 8: return DHCPINFORM; case 9: return DHCPFORCERENEW; case 10: return DHCPLEASEQUERY; case 11: return DHCPLEASEUNASSIGNED; case 12: return DHCPLEASEUNKNOWN; case 13: return DHCPLEASEACTIVE; } return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/ui/0000775000175000017500000000000012041336206024344 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/ui/web/0000775000175000017500000000000012041336206025121 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java0000664000175000017500000000410112041336206031343 0ustar jamespagejamespagepackage net.floodlightcontroller.ui.web; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import org.restlet.Client; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.data.Protocol; import org.restlet.resource.Directory; import org.restlet.routing.Router; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestletRoutable; public class StaticWebRoutable implements RestletRoutable, IFloodlightModule { private IRestApiService restApi; @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IRestApiService.class); return l; } @Override public Collection> getModuleServices() { return null; } @Override public Map, IFloodlightService> getServiceImpls() { return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { restApi = context.getServiceImpl(IRestApiService.class); } @Override public void startUp(FloodlightModuleContext context) { // Add our REST API restApi.addRestletRoutable(this); } @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("", new Directory(context, "clap://classloader/web/")); context.setClientDispatcher(new Client(context, Protocol.CLAP)); return router; } @Override public String basePath() { return "/ui/"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/0000775000175000017500000000000012041336206025662 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/PendingSwitchResp.java0000664000175000017500000000111012041336206032116 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType; /** * The Class PendingSwitchResp. This object is used to track the pending * responses to switch flow table queries. */ public class PendingSwitchResp { protected FCQueryEvType evType; public PendingSwitchResp( FCQueryEvType evType) { this.evType = evType; } public FCQueryEvType getEvType() { return evType; } public void setEvType(FCQueryEvType evType) { this.evType = evType; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java0000664000175000017500000001666312041336206032026 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import org.openflow.protocol.OFMatchWithSwDpid; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.FloodlightContextStore; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.core.module.IFloodlightService; /** * The Interface IFlowCache. *

* public interface APIs to Big Switch Flow-Cache Service. Flow-Cache maintains * the network-level flows that are currently deployed in the underlying * network. The flow cache can be queried using various filters by using the * corresponding APIs. * * @author subrata * */ public interface IFlowCacheService extends IFloodlightService { public static final String FLOWCACHE_APP_NAME = "net.floodlightcontroller.flowcache.appName"; public static final String FLOWCACHE_APP_INSTANCE_NAME = "net.floodlightcontroller.flowcache.appInstanceName"; /** * The flow cache query event type indicating the event that triggered the * query. The callerOpaqueObj can be keyed based on this event type */ public static enum FCQueryEvType { /** The GET query. Flows need not be reconciled for this query type */ GET, /** A new App was added. */ APP_ADDED, /** An App was deleted. */ APP_DELETED, /** Interface rule of an app was modified */ APP_INTERFACE_RULE_CHANGED, /** Some App configuration was changed */ APP_CONFIG_CHANGED, /** An ACL was added */ ACL_ADDED, /** An ACL was deleted */ ACL_DELETED, /** An ACL rule was added */ ACL_RULE_ADDED, /** An ACL rule was deleted */ ACL_RULE_DELETED, /** ACL configuration was changed */ ACL_CONFIG_CHANGED, /** device had moved to a different port in the network */ DEVICE_MOVED, /** device's property had changed, such as tag assignment */ DEVICE_PROPERTY_CHANGED, /** Link down */ LINK_DOWN, /** Periodic scan of switch flow table */ PERIODIC_SCAN, } /** * A FloodlightContextStore object that can be used to interact with the * FloodlightContext information about flowCache. */ public static final FloodlightContextStore fcStore = new FloodlightContextStore(); /** * Submit a flow cache query with query parameters specified in FCQueryObj * object. The query object can be created using one of the newFCQueryObj * helper functions in IFlowCache interface. *

* The queried flows are returned via the flowQueryRespHandler() callback * that the caller must implement. The caller can match the query with * the response using unique callerOpaqueData which remains unchanged * in the request and response callback. * * @see com.bigswitch.floodlight.flowcache#flowQueryRespHandler * @param query the flow cache query object as input * */ public void submitFlowCacheQuery(FCQueryObj query); /** * Deactivates all flows in the flow cache for which the source switch * matches the given switchDpid. Note that the flows are NOT deleted * from the cache. * * @param switchDpid Data-path identifier of the source switch */ public void deactivateFlowCacheBySwitch(long switchDpid); /** * Deletes all flows in the flow cache for which the source switch * matches the given switchDpid. * * @param switchDpid Data-path identifier of the source switch */ public void deleteFlowCacheBySwitch(long switchDpid); /** * Add a flow to the flow-cache - called when a flow-mod is about to be * written to a set of switches. If it returns false then it should not * be written to the switches. If it returns true then the cookie returned * should be used for the flow mod sent to the switches. * * @param appInstName Application instance name * @param ofm openflow match object * @param cookie openflow-mod cookie * @param swPort SwitchPort object * @param priority openflow match priority * @param action action taken on the matched packets (PERMIT or DENY) * @return true: flow should be written to the switch(es) * false: flow should not be written to the switch(es). false is * returned, for example, when the flow was recently * written to the flow-cache and hence it is dampened to * avoid frequent writes of the same flow to the switches * This case can typically arise for the flows written at the * internal ports as they are heavily wild-carded. */ public boolean addFlow(String appInstName, OFMatchWithSwDpid ofm, Long cookie, long srcSwDpid, short inPort, short priority, byte action); /** * Add a flow to the flow-cache - called when a flow-mod is about to be * written to a set of switches. If it returns false then it should not * be written to the switches. If it returns true then the cookie returned * should be used for the flow mod sent to the switches. * * @param cntx the cntx * @param ofm the ofm * @param cookie the cookie * @param swPort the sw port * @param priority the priority * @param action the action * @return true: flow should be written to the switch(es) * false: flow should not be written to the switch(es). false is * returned, for example, when the flow was recently * written to the flow-cache and hence it is dampened to * avoid frequent writes of the same flow to the switches * This case can typically arise for the flows written at the * internal ports as they are heavily wild-carded. */ public boolean addFlow(FloodlightContext cntx, OFMatchWithSwDpid ofm, Long cookie, SwitchPort swPort, short priority, byte action); /** * Move the specified flow from its current application instance to a * different application instance. This API can be used when a flow moves * to a different application instance when the application instance * configuration changes or when a device moves to a different part in * the network that belongs to a different application instance. *

* Note that, if the flow was not found in the current application * instance then the flow is not moved to the new application instance. * * @param ofMRc the object containing the flow match and new application * instance name. * @return true is the flow was found in the flow cache in the current * application instance; false if the flow was not found in the flow-cache * in the current application instance. */ public boolean moveFlowToDifferentApplInstName(OFMatchReconcile ofMRc); /** * Delete all flow from the specified switch * @param sw */ public void deleteAllFlowsAtASourceSwitch(IOFSwitch sw); /** * Post a request to update flowcache from a switch. * This is an asynchronous operation. * It queries the switch for stats and updates the flowcache asynchronously * with the response. * @param swDpid * @param delay_ms */ public void querySwitchFlowTable(long swDpid); } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java0000664000175000017500000004030312041336206032553 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.ListenerDispatcher; import net.floodlightcontroller.core.util.SingletonTask; import net.floodlightcontroller.counter.CounterStore; import net.floodlightcontroller.counter.ICounter; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.counter.SimpleCounter; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType; import net.floodlightcontroller.flowcache.IFlowReconcileListener; import net.floodlightcontroller.flowcache.OFMatchReconcile; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.openflow.protocol.OFType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FlowReconcileManager implements IFloodlightModule, IFlowReconcileService { /** The logger. */ private static Logger logger = LoggerFactory.getLogger(FlowReconcileManager.class); /** Reference to dependent modules */ protected IThreadPoolService threadPool; protected ICounterStoreService counterStore; /** * The list of flow reconcile listeners that have registered to get * flow reconcile callbacks. Such callbacks are invoked, for example, when * a switch with existing flow-mods joins this controller and those flows * need to be reconciled with the current configuration of the controller. */ protected ListenerDispatcher flowReconcileListeners; /** A FIFO queue to keep all outstanding flows for reconciliation */ Queue flowQueue; /** Asynchronous task to feed the flowReconcile pipeline */ protected SingletonTask flowReconcileTask; String controllerPktInCounterName; protected SimpleCounter lastPacketInCounter; protected static int MAX_SYSTEM_LOAD_PER_SECOND = 50000; /** a minimum flow reconcile rate so that it won't stave */ protected static int MIN_FLOW_RECONCILE_PER_SECOND = 1000; /** once per second */ protected static int FLOW_RECONCILE_DELAY_MILLISEC = 10; protected Date lastReconcileTime; /** Config to enable or disable flowReconcile */ protected static final String EnableConfigKey = "enable"; protected boolean flowReconcileEnabled; public int flowReconcileThreadRunCount; @Override public synchronized void addFlowReconcileListener( IFlowReconcileListener listener) { flowReconcileListeners.addListener(OFType.FLOW_MOD, listener); if (logger.isTraceEnabled()) { StringBuffer sb = new StringBuffer(); sb.append("FlowMod listeners: "); for (IFlowReconcileListener l : flowReconcileListeners.getOrderedListeners()) { sb.append(l.getName()); sb.append(","); } logger.trace(sb.toString()); } } @Override public synchronized void removeFlowReconcileListener( IFlowReconcileListener listener) { flowReconcileListeners.removeListener(listener); } @Override public synchronized void clearFlowReconcileListeners() { flowReconcileListeners.clearListeners(); } /** * Add to-be-reconciled flow to the queue. * * @param ofmRcIn the ofm rc in */ public void reconcileFlow(OFMatchReconcile ofmRcIn) { if (ofmRcIn == null) return; // Make a copy before putting on the queue. OFMatchReconcile myOfmRc = new OFMatchReconcile(ofmRcIn); flowQueue.add(myOfmRc); Date currTime = new Date(); long delay = 0; /** schedule reconcile task immidiately if it has been more than 1 sec * since the last run. Otherwise, schedule the reconcile task in * DELAY_MILLISEC. */ if (currTime.after(new Date(lastReconcileTime.getTime() + 1000))) { delay = 0; } else { delay = FLOW_RECONCILE_DELAY_MILLISEC; } flowReconcileTask.reschedule(delay, TimeUnit.MILLISECONDS); if (logger.isTraceEnabled()) { logger.trace("Reconciling flow: {}, total: {}", myOfmRc.toString(), flowQueue.size()); } } @Override public void updateFlowForDestinationDevice(IDevice device, IFlowQueryHandler handler, FCQueryEvType fcEvType) { // NO-OP } @Override public void updateFlowForSourceDevice(IDevice device, IFlowQueryHandler handler, FCQueryEvType fcEvType) { // NO-OP } @Override public void flowQueryGenericHandler(FlowCacheQueryResp flowResp) { if (flowResp.queryObj.evType != FCQueryEvType.GET) { OFMatchReconcile ofmRc = new OFMatchReconcile();; /* Re-provision these flows */ for (QRFlowCacheObj entry : flowResp.qrFlowCacheObjList) { /* reconcile the flows in entry */ entry.toOFMatchReconcile(ofmRc, flowResp.queryObj.applInstName, OFMatchReconcile.ReconcileAction.UPDATE_PATH); reconcileFlow(ofmRc); } } return; } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IFlowReconcileService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IFlowReconcileService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IThreadPoolService.class); l.add(ICounterStoreService.class); return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { threadPool = context.getServiceImpl(IThreadPoolService.class); counterStore = context.getServiceImpl(ICounterStoreService.class); flowQueue = new ConcurrentLinkedQueue(); flowReconcileListeners = new ListenerDispatcher(); Map configParam = context.getConfigParams(this); String enableValue = configParam.get(EnableConfigKey); // Set flowReconcile default to true flowReconcileEnabled = true; if (enableValue != null && enableValue.equalsIgnoreCase("false")) { flowReconcileEnabled = false; } flowReconcileThreadRunCount = 0; lastReconcileTime = new Date(0); logger.debug("FlowReconcile is {}", flowReconcileEnabled); } @Override public void startUp(FloodlightModuleContext context) { // thread to do flow reconcile ScheduledExecutorService ses = threadPool.getScheduledExecutor(); flowReconcileTask = new SingletonTask(ses, new Runnable() { @Override public void run() { try { if (doReconcile()) { flowReconcileTask.reschedule( FLOW_RECONCILE_DELAY_MILLISEC, TimeUnit.MILLISECONDS); } } catch (Exception e) { logger.warn("Exception in doReconcile(): {}", e.getMessage()); e.printStackTrace(); } } }); String packetInName = OFType.PACKET_IN.toClass().getName(); packetInName = packetInName.substring(packetInName.lastIndexOf('.')+1); // Construct controller counter for the packet_in controllerPktInCounterName = CounterStore.createCounterName(ICounterStoreService.CONTROLLER_NAME, -1, packetInName); } /** * Feed the flows into the flow reconciliation pipeline. * @return true if more flows to be reconciled * false if no more flows to be reconciled. */ protected boolean doReconcile() { if (!flowReconcileEnabled) { return false; } // Record the execution time. lastReconcileTime = new Date(); ArrayList ofmRcList = new ArrayList(); // Get the maximum number of flows that can be reconciled. int reconcileCapacity = getCurrentCapacity(); if (logger.isTraceEnabled()) { logger.trace("Reconcile capacity {} flows", reconcileCapacity); } while (!flowQueue.isEmpty() && reconcileCapacity > 0) { OFMatchReconcile ofmRc = flowQueue.poll(); reconcileCapacity--; if (ofmRc != null) { ofmRcList.add(ofmRc); if (logger.isTraceEnabled()) { logger.trace("Add flow {} to be the reconcileList", ofmRc.cookie); } } else { break; } } // Run the flow through all the flow reconcile listeners IFlowReconcileListener.Command retCmd; if (ofmRcList.size() > 0) { List listeners = flowReconcileListeners.getOrderedListeners(); if (listeners == null) { if (logger.isTraceEnabled()) { logger.trace("No flowReconcile listener"); } return false; } for (IFlowReconcileListener flowReconciler : flowReconcileListeners.getOrderedListeners()) { if (logger.isTraceEnabled()) { logger.trace("Reconciling flow: call listener {}", flowReconciler.getName()); } retCmd = flowReconciler.reconcileFlows(ofmRcList); if (retCmd == IFlowReconcileListener.Command.STOP) { break; } } flowReconcileThreadRunCount++; } else { if (logger.isTraceEnabled()) { logger.trace("No flow to be reconciled."); } } // Return true if there are more flows to be reconciled if (flowQueue.isEmpty()) { return false; } else { if (logger.isTraceEnabled()) { logger.trace("{} more flows to be reconciled.", flowQueue.size()); } return true; } } /** * Compute the maximum number of flows to be reconciled. * * It computes the packetIn increment from the counter values in * the counter store; * Then computes the rate based on the elapsed time * from the last query; * Then compute the max flow reconcile rate by subtracting the packetIn * rate from the hard-coded max system rate. * If the system rate is reached or less than MIN_FLOW_RECONCILE_PER_SECOND, * set the maximum flow reconcile rate to the MIN_FLOW_RECONCILE_PER_SECOND * to prevent starvation. * Then convert the rate to an absolute number for the * FLOW_RECONCILE_PERIOD. * @return */ protected int getCurrentCapacity() { ICounter pktInCounter = counterStore.getCounter(controllerPktInCounterName); int minFlows = MIN_FLOW_RECONCILE_PER_SECOND * FLOW_RECONCILE_DELAY_MILLISEC / 1000; // If no packetInCounter, then there shouldn't be any flow. if (pktInCounter == null || pktInCounter.getCounterDate() == null || pktInCounter.getCounterValue() == null) { logger.debug("counter {} doesn't exist", controllerPktInCounterName); return minFlows; } // Haven't get any counter yet. if (lastPacketInCounter == null) { logger.debug("First time get the count for {}", controllerPktInCounterName); lastPacketInCounter = (SimpleCounter) SimpleCounter.createCounter(pktInCounter); return minFlows; } int pktInRate = getPktInRate(pktInCounter, new Date()); // Update the last packetInCounter lastPacketInCounter = (SimpleCounter) SimpleCounter.createCounter(pktInCounter); int capacity = minFlows; if ((pktInRate + MIN_FLOW_RECONCILE_PER_SECOND) <= MAX_SYSTEM_LOAD_PER_SECOND) { capacity = (MAX_SYSTEM_LOAD_PER_SECOND - pktInRate) * FLOW_RECONCILE_DELAY_MILLISEC / 1000; } if (logger.isTraceEnabled()) { logger.trace("Capacity is {}", capacity); } return capacity; } protected int getPktInRate(ICounter newCnt, Date currentTime) { if (newCnt == null || newCnt.getCounterDate() == null || newCnt.getCounterValue() == null) { return 0; } // Somehow the system time is messed up. return max packetIn rate // to reduce the system load. if (newCnt.getCounterDate().before( lastPacketInCounter.getCounterDate())) { logger.debug("Time is going backward. new {}, old {}", newCnt.getCounterDate(), lastPacketInCounter.getCounterDate()); return MAX_SYSTEM_LOAD_PER_SECOND; } long elapsedTimeInSecond = (currentTime.getTime() - lastPacketInCounter.getCounterDate().getTime()) / 1000; if (elapsedTimeInSecond == 0) { // This should never happen. Check to avoid division by zero. return 0; } long diff = 0; switch (newCnt.getCounterValue().getType()) { case LONG: long newLong = newCnt.getCounterValue().getLong(); long oldLong = lastPacketInCounter.getCounterValue().getLong(); if (newLong < oldLong) { // Roll over event diff = Long.MAX_VALUE - oldLong + newLong; } else { diff = newLong - oldLong; } break; case DOUBLE: double newDouble = newCnt.getCounterValue().getDouble(); double oldDouble = lastPacketInCounter.getCounterValue().getDouble(); if (newDouble < oldDouble) { // Roll over event diff = (long)(Double.MAX_VALUE - oldDouble + newDouble); } else { diff = (long)(newDouble - oldDouble); } break; } return (int)(diff/elapsedTimeInSecond); } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java0000664000175000017500000000542712041336206031642 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import net.floodlightcontroller.core.FloodlightContext; import org.openflow.protocol.OFMatchWithSwDpid; /** * OFMatchReconcile class to indicate result of a flow-reconciliation. */ public class OFMatchReconcile { /** * The enum ReconcileAction. Specifies the result of reconciliation of a * flow. */ public enum ReconcileAction { /** Delete the flow-mod from the switch */ DROP, /** Leave the flow-mod as-is. */ NO_CHANGE, /** Program this new flow mod. */ NEW_ENTRY, /** * Reprogram the flow mod as the path of the flow might have changed, * for example when a host is moved or when a link goes down. */ UPDATE_PATH, /* Flow is now in a different BVS */ APP_INSTANCE_CHANGED, /* Delete the flow-mod - used to delete, for example, drop flow-mods * when the source and destination are in the same BVS after a * configuration change */ DELETE } /** The open flow match after reconciliation. */ public OFMatchWithSwDpid ofmWithSwDpid; /** flow mod. priority */ public short priority; /** Action of this flow-mod PERMIT or DENY */ public byte action; /** flow mod. cookie */ public long cookie; /** The application instance name. */ public String appInstName; /** * The new application instance name. This is null unless the flow * has moved to a different BVS due to BVS config change or device * move to a different switch port etc.*/ public String newAppInstName; /** The reconcile action. */ public ReconcileAction rcAction; // The context for the reconcile action public FloodlightContext cntx; /** * Instantiates a new oF match reconcile object. */ public OFMatchReconcile() { ofmWithSwDpid = new OFMatchWithSwDpid(); rcAction = ReconcileAction.NO_CHANGE; cntx = new FloodlightContext(); } public OFMatchReconcile(OFMatchReconcile copy) { ofmWithSwDpid = new OFMatchWithSwDpid(copy.ofmWithSwDpid.getOfMatch(), copy.ofmWithSwDpid.getSwitchDataPathId()); priority = copy.priority; action = copy.action; cookie = copy.cookie; appInstName = copy.appInstName; newAppInstName = copy.newAppInstName; rcAction = copy.rcAction; cntx = new FloodlightContext(); } @Override public String toString() { return "OFMatchReconcile [" + ofmWithSwDpid + " priority=" + priority + " action=" + action + " cookie=" + cookie + " appInstName=" + appInstName + " newAppInstName=" + newAppInstName + " ReconcileAction=" + rcAction + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/IFlowQueryHandler.java0000664000175000017500000000200112041336206032062 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; public interface IFlowQueryHandler { /** * This callback function is called in response to a flow query request * submitted to the flow cache service. The module handling this callback * can be different from the one that submitted the query. In the flow * query object used for submitting the flow query, the identity of the * callback handler is passed. When flow cache service has all or some * of the flows that needs to be returned then this callback is called * for the appropriate module. The respone contains a boolean more flag * that indicates if there are additional flows that may be returned * via additional callback calls. * * @param resp the response object containing the original flow query * object, partial or complete list of flows that we queried and some * metadata such as the more flag described aboce. * */ public void flowQueryRespHandler(FlowCacheQueryResp resp); } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/QRFlowCacheObj.java0000664000175000017500000000412512041336206031260 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import org.openflow.protocol.OFMatchWithSwDpid; /** * Used in BigFlowCacheQueryResp as query result. * Used to return one flow when queried by one of the big flow cache APIs. * One of these QRFlowCacheObj is returned for each combination of * priority and action. * * @author subrata */ public class QRFlowCacheObj { /** The open flow match object. */ public OFMatchWithSwDpid ofmWithSwDpid; /** The flow-mod priority. */ public short priority; /** flow-mod cookie */ public long cookie; /** The action - PERMIT or DENY. */ public byte action; /** The reserved byte to align with 8 bytes. */ public byte reserved; /** * Instantiates a new flow cache query object. * * @param priority the priority * @param action the action */ public QRFlowCacheObj(short priority, byte action, long cookie) { ofmWithSwDpid = new OFMatchWithSwDpid(); this.action = action; this.priority = priority; this.cookie = cookie; } /** * Populate a given OFMatchReconcile object from the values of this * class. * * @param ofmRc the given OFMatchReconcile object * @param appInstName the application instance name * @param rcAction the reconcile action */ public void toOFMatchReconcile(OFMatchReconcile ofmRc, String appInstName, OFMatchReconcile.ReconcileAction rcAction) { ofmRc.ofmWithSwDpid = ofmWithSwDpid; // not copying ofmRc.appInstName = appInstName; ofmRc.rcAction = rcAction; ofmRc.priority = priority; ofmRc.cookie = cookie; ofmRc.action = action; } @Override public String toString() { String str = "ofmWithSwDpid: " + this.ofmWithSwDpid.toString() + " "; str += "priority: " + this.priority + " "; str += "cookie: " + this.cookie + " "; str += "action: " + this.action + " "; str += "reserved: " + this.reserved + " "; return str; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/FCQueryObj.java0000664000175000017500000000744212041336206030505 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import java.util.Arrays; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType; /** * The Class FCQueryObj. */ public class FCQueryObj { /** The caller of the flow cache query. */ public IFlowQueryHandler fcQueryHandler; /** The application instance name. */ public String applInstName; /** The vlan Id. */ public Short[] vlans; /** The destination device. */ public IDevice dstDevice; /** The source device. */ public IDevice srcDevice; /** The caller name */ public String callerName; /** Event type that triggered this flow query submission */ public FCQueryEvType evType; /** The caller opaque data. Returned unchanged in the query response * via the callback. The type of this object could be different for * different callers */ public Object callerOpaqueObj; /** * Instantiates a new flow cache query object */ public FCQueryObj(IFlowQueryHandler fcQueryHandler, String applInstName, Short vlan, IDevice srcDevice, IDevice dstDevice, String callerName, FCQueryEvType evType, Object callerOpaqueObj) { this.fcQueryHandler = fcQueryHandler; this.applInstName = applInstName; this.srcDevice = srcDevice; this.dstDevice = dstDevice; this.callerName = callerName; this.evType = evType; this.callerOpaqueObj = callerOpaqueObj; if (vlan != null) { this.vlans = new Short[] { vlan }; } else { if (srcDevice != null) { this.vlans = srcDevice.getVlanId(); } else if (dstDevice != null) { this.vlans = dstDevice.getVlanId(); } } } @Override public String toString() { return "FCQueryObj [fcQueryCaller=" + fcQueryHandler + ", applInstName=" + applInstName + ", vlans=" + Arrays.toString(vlans) + ", dstDevice=" + dstDevice + ", srcDevice=" + srcDevice + ", callerName=" + callerName + ", evType=" + evType + ", callerOpaqueObj=" + callerOpaqueObj + "]"; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; FCQueryObj other = (FCQueryObj) obj; if (applInstName == null) { if (other.applInstName != null) return false; } else if (!applInstName.equals(other.applInstName)) return false; if (callerName == null) { if (other.callerName != null) return false; } else if (!callerName.equals(other.callerName)) return false; if (callerOpaqueObj == null) { if (other.callerOpaqueObj != null) return false; } else if (!callerOpaqueObj.equals(other.callerOpaqueObj)) return false; if (dstDevice == null) { if (other.dstDevice != null) return false; } else if (!dstDevice.equals(other.dstDevice)) return false; if (evType != other.evType) return false; if (fcQueryHandler != other.fcQueryHandler) return false; if (srcDevice == null) { if (other.srcDevice != null) return false; } else if (!srcDevice.equals(other.srcDevice)) return false; if (!Arrays.equals(vlans, other.vlans)) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java0000664000175000017500000000177012041336206031733 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; public class PendingSwRespKey { long swDpid; int transId; public PendingSwRespKey(long swDpid, int transId) { this.swDpid = swDpid; this.transId = transId; } @Override public int hashCode() { final int prime = 97; Long dpid = swDpid; Integer tid = transId; return (tid.hashCode()*prime + dpid.hashCode()); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof PendingSwRespKey)) { return false; } PendingSwRespKey other = (PendingSwRespKey) obj; if ((swDpid != other.swDpid) || (transId != other.transId)) { return false; } return true; } @Override public String toString() { return Long.toHexString(swDpid)+","+Integer.toString(transId); } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/FlowCacheQueryResp.java0000664000175000017500000000310612041336206032240 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import java.util.ArrayList; /** * Object to return flows in response to a query message to BigFlowCache. * This object is passed in the flowQueryRespHandler() callback. */ public class FlowCacheQueryResp { /** query object provided by the caller, returned unchanged. */ public FCQueryObj queryObj; /** * Set to true if more flows could be returned for this query in * additional callbacks. Set of false in the last callback for the * query. */ public boolean moreFlag; /** * Set to true if the response has been sent to handler */ public boolean hasSent; /** * The flow list. If there are large number of flows to be returned * then they may be returned in multiple callbacks. */ public ArrayList qrFlowCacheObjList; /** * Instantiates a new big flow cache query response. * * @param query the flow cache query object as given by the caller of * flow cache submit query API. */ public FlowCacheQueryResp(FCQueryObj query) { qrFlowCacheObjList = new ArrayList(); queryObj = query; moreFlag = false; hasSent = false; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { String s = queryObj.toString() + "; moreFlasg=" + moreFlag + "; hasSent=" + hasSent; s += "; FlowCount=" + Integer.toString(qrFlowCacheObjList.size()); return s; } } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java0000664000175000017500000000323212041336206033077 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import java.util.ArrayList; import net.floodlightcontroller.core.IListener; import org.openflow.protocol.OFType; /** * The Interface IFlowReconciler. * * @author subrata */ public interface IFlowReconcileListener extends IListener { /** * Given an input OFMatch, this method applies the policy of the reconciler * and returns a the same input OFMatch structure modified. Additional * OFMatches, if needed, are returned in OFMatch-list. All the OFMatches * are assumed to have "PERMIT" action. * * @param ofmRcList input flow matches, to be updated to be consistent with * the policies of this reconciler * Additional OFMatch-es can be added to the "list" as * needed. * For example after a new ACL application, one flow-match * may result in multiple flow-matches * The method must also update the ReconcileAction * member in ofmRcList entries to indicate if the * flow needs to be modified, deleted or left unchanged * OR of a new entry is to be added after flow * reconciliation * * * @return Command.CONTINUE if the OFMatch should be sent to the * next flow reconciler. * Command.STOP if the OFMatch shouldn't be processed * further. In this case the no reconciled flow-mods would * be programmed */ public Command reconcileFlows(ArrayList ofmRcList); } floodlight-0.90/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java0000664000175000017500000000502312041336206032712 0ustar jamespagejamespage/** * Provides Flow Reconcile service to other modules that need to reconcile * flows. */ package net.floodlightcontroller.flowcache; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.flowcache.IFlowCacheService.FCQueryEvType; public interface IFlowReconcileService extends IFloodlightService { /** * Add a flow reconcile listener * @param listener The module that can reconcile flows */ public void addFlowReconcileListener(IFlowReconcileListener listener); /** * Remove a flow reconcile listener * @param listener The module that no longer reconcile flows */ public void removeFlowReconcileListener(IFlowReconcileListener listener); /** * Remove all flow reconcile listeners */ public void clearFlowReconcileListeners(); /** * Reconcile flow. Returns false if no modified flow-mod need to be * programmed if cluster ID is providced then pnly flows in the given * cluster are reprogrammed * * @param ofmRcIn the ofm rc in */ public void reconcileFlow(OFMatchReconcile ofmRcIn); /** * Updates the flows to a device after the device moved to a new location *

* Queries the flow-cache to get all the flows destined to the given device. * Reconciles each of these flows by potentially reprogramming them to its * new attachment point * * @param device device that has moved * @param handler handler to process the flows * @param fcEvType Event type that triggered the update * */ public void updateFlowForDestinationDevice(IDevice device, IFlowQueryHandler handler, FCQueryEvType fcEvType); /** * Updates the flows from a device *

* Queries the flow-cache to get all the flows source from the given device. * Reconciles each of these flows by potentially reprogramming them to its * new attachment point * * @param device device where the flow originates * @param handler handler to process the flows * @param fcEvType Event type that triggered the update * */ public void updateFlowForSourceDevice(IDevice device, IFlowQueryHandler handler, FCQueryEvType fcEvType); /** * Generic flow query handler to insert FlowMods into the reconcile pipeline. * @param flowResp */ public void flowQueryGenericHandler(FlowCacheQueryResp flowResp); } floodlight-0.90/src/main/java/net/floodlightcontroller/restserver/0000775000175000017500000000000012041336206026133 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/restserver/IRestApiService.java0000664000175000017500000000056412041336206032004 0ustar jamespagejamespagepackage net.floodlightcontroller.restserver; import net.floodlightcontroller.core.module.IFloodlightService; public interface IRestApiService extends IFloodlightService { /** * Adds a REST API * @param routeable */ public void addRestletRoutable(RestletRoutable routable); /** * Runs the REST API server */ public void run(); } floodlight-0.90/src/main/java/net/floodlightcontroller/restserver/RestApiServer.java0000664000175000017500000001471212041336206031541 0ustar jamespagejamespagepackage net.floodlightcontroller.restserver; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.restlet.Application; import org.restlet.Component; import org.restlet.Context; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.Protocol; import org.restlet.data.Reference; import org.restlet.data.Status; import org.restlet.ext.jackson.JacksonRepresentation; import org.restlet.representation.Representation; import org.restlet.routing.Filter; import org.restlet.routing.Router; import org.restlet.routing.Template; import org.restlet.service.StatusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; public class RestApiServer implements IFloodlightModule, IRestApiService { protected static Logger logger = LoggerFactory.getLogger(RestApiServer.class); protected List restlets; protected FloodlightModuleContext fmlContext; protected int restPort = 8080; // *********** // Application // *********** protected class RestApplication extends Application { protected Context context; public RestApplication() { super(new Context()); this.context = getContext(); } @Override public Restlet createInboundRoot() { Router baseRouter = new Router(context); baseRouter.setDefaultMatchingMode(Template.MODE_STARTS_WITH); for (RestletRoutable rr : restlets) { baseRouter.attach(rr.basePath(), rr.getRestlet(context)); } Filter slashFilter = new Filter() { @Override protected int beforeHandle(Request request, Response response) { Reference ref = request.getResourceRef(); String originalPath = ref.getPath(); if (originalPath.contains("//")) { String newPath = originalPath.replaceAll("/+", "/"); ref.setPath(newPath); } return Filter.CONTINUE; } }; slashFilter.setNext(baseRouter); return slashFilter; } public void run(FloodlightModuleContext fmlContext, int restPort) { setStatusService(new StatusService() { @Override public Representation getRepresentation(Status status, Request request, Response response) { return new JacksonRepresentation(status); } }); // Add everything in the module context to the rest for (Class s : fmlContext.getAllServices()) { if (logger.isTraceEnabled()) { logger.trace("Adding {} for service {} into context", s.getCanonicalName(), fmlContext.getServiceImpl(s)); } context.getAttributes().put(s.getCanonicalName(), fmlContext.getServiceImpl(s)); } // Start listening for REST requests try { final Component component = new Component(); component.getServers().add(Protocol.HTTP, restPort); component.getClients().add(Protocol.CLAP); component.getDefaultHost().attach(this); component.start(); } catch (Exception e) { throw new RuntimeException(e); } } } // *************** // IRestApiService // *************** @Override public void addRestletRoutable(RestletRoutable routable) { restlets.add(routable); } @Override public void run() { if (logger.isDebugEnabled()) { StringBuffer sb = new StringBuffer(); sb.append("REST API routables: "); for (RestletRoutable routable : restlets) { sb.append(routable.getClass().getSimpleName()); sb.append(" ("); sb.append(routable.basePath()); sb.append("), "); } logger.debug(sb.toString()); } RestApplication restApp = new RestApplication(); restApp.run(fmlContext, restPort); } // ***************** // IFloodlightModule // ***************** @Override public Collection> getModuleServices() { Collection> services = new ArrayList>(1); services.add(IRestApiService.class); return services; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IRestApiService.class, this); return m; } @Override public Collection> getModuleDependencies() { // We don't have any return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { // This has to be done here since we don't know what order the // startUp methods will be called this.restlets = new ArrayList(); this.fmlContext = context; // read our config options Map configOptions = context.getConfigParams(this); String port = configOptions.get("port"); if (port != null) { restPort = Integer.parseInt(port); } logger.debug("REST port set to {}", restPort); } @Override public void startUp(FloodlightModuleContext Context) { // no-op } }floodlight-0.90/src/main/java/net/floodlightcontroller/restserver/RestletRoutable.java0000664000175000017500000000243512041336206032122 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.restserver; import org.restlet.Context; import org.restlet.Restlet; /** * Register a set of REST resources with the central controller * @author readams */ public interface RestletRoutable { /** * Get the restlet that will map to the resources * @param context the context for constructing the restlet * @return the restlet */ Restlet getRestlet(Context context); /** * Get the base path URL where the router should be registered * @return the base path URL where the router should be registered */ String basePath(); } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/0000775000175000017500000000000012041336206025416 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/routing/Route.java0000775000175000017500000000606412041336206027370 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import java.util.ArrayList; import java.util.List; import net.floodlightcontroller.topology.NodePortTuple; /** * Represents a route between two switches * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class Route implements Comparable { protected RouteId id; protected List switchPorts; public Route(RouteId id, List switchPorts) { super(); this.id = id; this.switchPorts = switchPorts; } public Route(Long src, Long dst) { super(); this.id = new RouteId(src, dst); this.switchPorts = new ArrayList(); } /** * @return the id */ public RouteId getId() { return id; } /** * @param id the id to set */ public void setId(RouteId id) { this.id = id; } /** * @return the path */ public List getPath() { return switchPorts; } /** * @param path the path to set */ public void setPath(List switchPorts) { this.switchPorts = switchPorts; } @Override public int hashCode() { final int prime = 5791; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((switchPorts == null) ? 0 : switchPorts.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Route other = (Route) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (switchPorts == null) { if (other.switchPorts != null) return false; } else if (!switchPorts.equals(other.switchPorts)) return false; return true; } @Override public String toString() { return "Route [id=" + id + ", switchPorts=" + switchPorts + "]"; } /** * Compares the path lengths between Routes. */ @Override public int compareTo(Route o) { return ((Integer)switchPorts.size()).compareTo(o.switchPorts.size()); } } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/RouteId.java0000775000175000017500000000530712041336206027644 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import org.openflow.util.HexString; /** * Stores the endpoints of a route, in this case datapath ids * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class RouteId implements Cloneable, Comparable { protected Long src; protected Long dst; public RouteId(Long src, Long dst) { super(); this.src = src; this.dst = dst; } public Long getSrc() { return src; } public void setSrc(Long src) { this.src = src; } public Long getDst() { return dst; } public void setDst(Long dst) { this.dst = dst; } @Override public int hashCode() { final int prime = 2417; int result = 1; result = prime * result + ((dst == null) ? 0 : dst.hashCode()); result = prime * result + ((src == null) ? 0 : src.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; RouteId other = (RouteId) obj; if (dst == null) { if (other.dst != null) return false; } else if (!dst.equals(other.dst)) return false; if (src == null) { if (other.src != null) return false; } else if (!src.equals(other.src)) return false; return true; } @Override public String toString() { return "RouteId [src=" + HexString.toHexString(this.src) + " dst=" + HexString.toHexString(this.dst) + "]"; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public int compareTo(RouteId o) { int result = src.compareTo(o.getSrc()); if (result != 0) return result; return dst.compareTo(o.getDst()); } } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java0000664000175000017500000000364412041336206031012 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import java.util.HashMap; import net.floodlightcontroller.routing.Link; import org.openflow.util.HexString; public class BroadcastTree { protected HashMap links; protected HashMap costs; public BroadcastTree() { links = new HashMap(); costs = new HashMap(); } public BroadcastTree(HashMap links, HashMap costs) { this.links = links; this.costs = costs; } public Link getTreeLink(long node) { return links.get(node); } public int getCost(long node) { if (costs.get(node) == null) return -1; return (costs.get(node)); } public HashMap getLinks() { return links; } public void addTreeLink(long myNode, Link link) { links.put(myNode, link); } public String toString() { StringBuffer sb = new StringBuffer(); for(long n: links.keySet()) { sb.append("[" + HexString.toHexString(n) + ": cost=" + costs.get(n) + ", " + links.get(n) + "]"); } return sb.toString(); } public HashMap getCosts() { return costs; } } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java0000664000175000017500000000535512041336206031507 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import java.util.List; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.FloodlightContextStore; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.SwitchPort; public interface IRoutingDecision { public enum RoutingAction { /* * NONE: NO-OP, continue with the packet processing chain * DROP: Drop this packet and this flow * FORWARD: Forward this packet, and this flow, to the first (and only device) in getDestinationDevices(), * if the destination is not known at this time, initiate a discovery action for it (e.g. ARP) * FORWARD_OR_FLOOD: Forward this packet, and this flow, to the first (and only device) in getDestinationDevices(), * if the destination is not known at this time, flood this packet on the source switch * BROADCAST: Broadcast this packet on all links * MULTICAST: Multicast this packet to all the interfaces and devices attached */ NONE, DROP, FORWARD, FORWARD_OR_FLOOD, BROADCAST, MULTICAST } public static final FloodlightContextStore rtStore = new FloodlightContextStore(); public static final String CONTEXT_DECISION = "net.floodlightcontroller.routing.decision"; public void addToContext(FloodlightContext cntx); public RoutingAction getRoutingAction(); public void setRoutingAction(RoutingAction action); public SwitchPort getSourcePort(); public IDevice getSourceDevice(); public List getDestinationDevices(); public void addDestinationDevice(IDevice d); public List getMulticastInterfaces(); public void setMulticastInterfaces(List lspt); public Integer getWildcards(); public void setWildcards(Integer wildcards); } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/Link.java0000775000175000017500000000672112041336206027167 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.core.web.serializers.UShortSerializer; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; public class Link { private long src; private short srcPort; private long dst; private short dstPort; public Link(long srcId, short srcPort, long dstId, short dstPort) { this.src = srcId; this.srcPort = srcPort; this.dst = dstId; this.dstPort = dstPort; } // Convenience method public Link(long srcId, int srcPort, long dstId, int dstPort) { this.src = srcId; this.srcPort = (short) srcPort; this.dst = dstId; this.dstPort = (short) dstPort; } @JsonProperty("src-switch") @JsonSerialize(using=DPIDSerializer.class) public long getSrc() { return src; } @JsonProperty("src-port") @JsonSerialize(using=UShortSerializer.class) public short getSrcPort() { return srcPort; } @JsonProperty("dst-switch") @JsonSerialize(using=DPIDSerializer.class) public long getDst() { return dst; } @JsonProperty("dst-port") @JsonSerialize(using=UShortSerializer.class) public short getDstPort() { return dstPort; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (dst ^ (dst >>> 32)); result = prime * result + dstPort; result = prime * result + (int) (src ^ (src >>> 32)); result = prime * result + srcPort; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Link other = (Link) obj; if (dst != other.dst) return false; if (dstPort != other.dstPort) return false; if (src != other.src) return false; if (srcPort != other.srcPort) return false; return true; } @Override public String toString() { return "Link [src=" + HexString.toHexString(this.src) + " outPort=" + (srcPort & 0xffff) + ", dst=" + HexString.toHexString(this.dst) + ", inPort=" + (dstPort & 0xffff) + "]"; } public String toKeyString() { return (HexString.toHexString(this.src) + "|" + (this.srcPort & 0xffff) + "|" + HexString.toHexString(this.dst) + "|" + (this.dstPort & 0xffff) ); } } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java0000664000175000017500000000510512041336206031367 0ustar jamespagejamespagepackage net.floodlightcontroller.routing; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.SwitchPort; public class RoutingDecision implements IRoutingDecision { protected RoutingAction action; protected Integer wildcards; protected SwitchPort srcPort; protected IDevice srcDevice; protected List destDevices; protected List broadcastIntertfaces; public RoutingDecision(long swDipd, short inPort, IDevice srcDevice, RoutingAction action) { this.srcPort = new SwitchPort(swDipd, inPort); this.srcDevice = srcDevice; this.destDevices = Collections.synchronizedList(new ArrayList()); this.broadcastIntertfaces = Collections.synchronizedList(new ArrayList()); this.action = action; this.wildcards = null; } @Override public RoutingAction getRoutingAction() { return this.action; } @Override public void setRoutingAction(RoutingAction action) { this.action = action; } @Override public SwitchPort getSourcePort() { return this.srcPort; } @Override public IDevice getSourceDevice() { return this.srcDevice; } @Override public List getDestinationDevices() { return this.destDevices; } @Override public void addDestinationDevice(IDevice d) { if (!destDevices.contains(d)) { destDevices.add(d); } } @Override public void setMulticastInterfaces(List lspt) { this.broadcastIntertfaces = lspt; } @Override public List getMulticastInterfaces() { return this.broadcastIntertfaces; } @Override public Integer getWildcards() { return this.wildcards; } @Override public void setWildcards(Integer wildcards) { this.wildcards = wildcards; } @Override public void addToContext(FloodlightContext cntx) { rtStore.put(cntx, IRoutingDecision.CONTEXT_DECISION, this); } public String toString() { return "action " + action + " wildcard " + ((wildcards == null) ? null : "0x"+Integer.toHexString(wildcards.intValue())); } } floodlight-0.90/src/main/java/net/floodlightcontroller/routing/IRoutingService.java0000664000175000017500000000347712041336206031355 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.routing.Route; public interface IRoutingService extends IFloodlightService { /** Provides a route between src and dst that allows tunnels. */ public Route getRoute(long src, long dst); /** Provides a route between src and dst, with option to allow or * not allow tunnels in the path.*/ public Route getRoute(long src, long dst, boolean tunnelEnabled); public Route getRoute(long srcId, short srcPort, long dstId, short dstPort); public Route getRoute(long srcId, short srcPort, long dstId, short dstPort, boolean tunnelEnabled); /** Check if a route exists between src and dst, including tunnel links * in the path. */ public boolean routeExists(long src, long dst); /** Check if a route exists between src and dst, with option to have * or not have tunnels as part of the path. */ public boolean routeExists(long src, long dst, boolean tunnelEnabled); }floodlight-0.90/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java0000664000175000017500000006453212041336206031170 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import java.io.IOException; import java.util.EnumSet; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceListener; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import net.floodlightcontroller.util.OFMessageDamper; import net.floodlightcontroller.util.TimedCache; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Abstract base class for implementing a forwarding module. Forwarding is * responsible for programming flows to a switch in response to a policy * decision. */ @LogMessageCategory("Flow Programming") public abstract class ForwardingBase implements IOFMessageListener, IDeviceListener { protected static Logger log = LoggerFactory.getLogger(ForwardingBase.class); protected static int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite protected IFloodlightProviderService floodlightProvider; protected IDeviceService deviceManager; protected IRoutingService routingEngine; protected ITopologyService topology; protected ICounterStoreService counterStore; protected OFMessageDamper messageDamper; // for broadcast loop suppression protected boolean broadcastCacheFeature = true; public final int prime1 = 2633; // for hash calculation public final static int prime2 = 4357; // for hash calculation public TimedCache broadcastCache = new TimedCache(100, 5*1000); // 5 seconds interval; // flow-mod - for use in the cookie public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed // by a global APP_ID class public long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); // Comparator for sorting by SwitchCluster public Comparator clusterIdComparator = new Comparator() { @Override public int compare(SwitchPort d1, SwitchPort d2) { Long d1ClusterId = topology.getL2DomainId(d1.getSwitchDPID()); Long d2ClusterId = topology.getL2DomainId(d2.getSwitchDPID()); return d1ClusterId.compareTo(d2ClusterId); } }; /** * init data structures * */ protected void init() { messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, EnumSet.of(OFType.FLOW_MOD), OFMESSAGE_DAMPER_TIMEOUT); } /** * Adds a listener for devicemanager and registers for PacketIns. */ protected void startUp() { deviceManager.addListener(this); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); } /** * Returns the application name "forwarding". */ @Override public String getName() { return "forwarding"; } /** * All subclasses must define this function if they want any specific * forwarding action * * @param sw * Switch that the packet came in from * @param pi * The packet that came in * @param decision * Any decision made by a policy engine */ public abstract Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx); @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: IRoutingDecision decision = null; if (cntx != null) decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx); default: break; } return Command.CONTINUE; } /** * Push routes from back to front * @param route Route to push * @param match OpenFlow fields to match on * @param srcSwPort Source switch port for the first hop * @param dstSwPort Destination switch port for final hop * @param cookie The cookie to set in each flow_mod * @param cntx The floodlight context * @param reqeustFlowRemovedNotifn if set to true then the switch would * send a flow mod removal notification when the flow mod expires * @param doFlush if set to true then the flow mod would be immediately * written to the switch * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD, * OFFlowMod.OFPFC_MODIFY etc. * @return srcSwitchIincluded True if the source switch is included in this route */ @LogMessageDocs({ @LogMessageDoc(level="WARN", message="Unable to push route, switch at DPID {dpid} not available", explanation="A switch along the calculated path for the " + "flow has disconnected.", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Failure writing flow mod", explanation="An I/O error occurred while writing a " + "flow modification to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) }) public boolean pushRoute(Route route, OFMatch match, Integer wildcard_hints, OFPacketIn pi, long pinSwitch, long cookie, FloodlightContext cntx, boolean reqeustFlowRemovedNotifn, boolean doFlush, short flowModCommand) { boolean srcSwitchIncluded = false; OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory() .getMessage(OFType.FLOW_MOD); OFActionOutput action = new OFActionOutput(); action.setMaxLength((short)0xffff); List actions = new ArrayList(); actions.add(action); fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(cookie) .setCommand(flowModCommand) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); List switchPortList = route.getPath(); for (int indx = switchPortList.size()-1; indx > 0; indx -= 2) { // indx and indx-1 will always have the same switch DPID. long switchDPID = switchPortList.get(indx).getNodeId(); IOFSwitch sw = floodlightProvider.getSwitches().get(switchDPID); if (sw == null) { if (log.isWarnEnabled()) { log.warn("Unable to push route, switch at DPID {} " + "not available", switchDPID); } return srcSwitchIncluded; } // set the match. fm.setMatch(wildcard(match, sw, wildcard_hints)); // set buffer id if it is the source switch if (1 == indx) { // Set the flag to request flow-mod removal notifications only for the // source switch. The removal message is used to maintain the flow // cache. Don't set the flag for ARP messages - TODO generalize check if ((reqeustFlowRemovedNotifn) && (match.getDataLayerType() != Ethernet.TYPE_ARP)) { fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM); match.setWildcards(fm.getMatch().getWildcards()); } } short outPort = switchPortList.get(indx).getPortId(); short inPort = switchPortList.get(indx-1).getPortId(); // set input and output ports on the switch fm.getMatch().setInputPort(inPort); ((OFActionOutput)fm.getActions().get(0)).setPort(outPort); try { counterStore.updatePktOutFMCounterStore(sw, fm); if (log.isTraceEnabled()) { log.trace("Pushing Route flowmod routeIndx={} " + "sw={} inPort={} outPort={}", new Object[] {indx, sw, fm.getMatch().getInputPort(), outPort }); } messageDamper.write(sw, fm, cntx); if (doFlush) { sw.flush(); } // Push the packet out the source switch if (sw.getId() == pinSwitch) { // TODO: Instead of doing a packetOut here we could also // send a flowMod with bufferId set.... pushPacket(sw, match, pi, outPort, cntx); srcSwitchIncluded = true; } } catch (IOException e) { log.error("Failure writing flow mod", e); } try { fm = fm.clone(); } catch (CloneNotSupportedException e) { log.error("Failure cloning flow mod", e); } } return srcSwitchIncluded; } protected OFMatch wildcard(OFMatch match, IOFSwitch sw, Integer wildcard_hints) { if (wildcard_hints != null) { return match.clone().setWildcards(wildcard_hints.intValue()); } return match.clone(); } /** * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we * assume that the packetOut switch is the same as the packetIn switch * and we will use the bufferId * Caller needs to make sure that inPort and outPort differs * @param packet packet data to send * @param sw switch from which packet-out is sent * @param bufferId bufferId * @param inPort input port * @param outPort output port * @param cntx context of the packet * @param flush force to flush the packet. */ @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="BufferId is not and packet data is null. " + "Cannot send packetOut. " + "srcSwitch={dpid} inPort={port} outPort={port}", explanation="The switch send a malformed packet-in." + "The packet will be dropped", recommendation=LogMessageDoc.REPORT_SWITCH_BUG), @LogMessageDoc(level="ERROR", message="Failure writing packet out", explanation="An I/O error occurred while writing a " + "packet out to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) }) public void pushPacket(IPacket packet, IOFSwitch sw, int bufferId, short inPort, short outPort, FloodlightContext cntx, boolean flush) { if (log.isTraceEnabled()) { log.trace("PacketOut srcSwitch={} inPort={} outPort={}", new Object[] {sw, inPort, outPort}); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory() .getMessage(OFType.PACKET_OUT); // set actions List actions = new ArrayList(); actions.add(new OFActionOutput(outPort, (short) 0xffff)); po.setActions(actions) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); // set buffer_id, in_port po.setBufferId(bufferId); po.setInPort(inPort); // set data - only if buffer_id == -1 if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { if (packet == null) { log.error("BufferId is not set and packet data is null. " + "Cannot send packetOut. " + "srcSwitch={} inPort={} outPort={}", new Object[] {sw, inPort, outPort}); return; } byte[] packetData = packet.serialize(); poLength += packetData.length; po.setPacketData(packetData); } po.setLength(poLength); try { counterStore.updatePktOutFMCounterStore(sw, po); messageDamper.write(sw, po, cntx, flush); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * Pushes a packet-out to a switch. The assumption here is that * the packet-in was also generated from the same switch. Thus, if the input * port of the packet-in and the outport are the same, the function will not * push the packet-out. * @param sw switch that generated the packet-in, and from which packet-out is sent * @param match OFmatch * @param pi packet-in * @param outport output port * @param cntx context of the packet */ protected void pushPacket(IOFSwitch sw, OFMatch match, OFPacketIn pi, short outport, FloodlightContext cntx) { if (pi == null) { return; } else if (pi.getInPort() == outport){ log.warn("Packet out not sent as the outport matches inport. {}", pi); return; } // The assumption here is (sw) is the switch that generated the // packet-in. If the input port is the same as output port, then // the packet-out should be ignored. if (pi.getInPort() == outport) { if (log.isDebugEnabled()) { log.debug("Attempting to do packet-out to the same " + "interface as packet-in. Dropping packet. " + " SrcSwitch={}, match = {}, pi={}", new Object[]{sw, match, pi}); return; } } if (log.isTraceEnabled()) { log.trace("PacketOut srcSwitch={} match={} pi={}", new Object[] {sw, match, pi}); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory() .getMessage(OFType.PACKET_OUT); // set actions List actions = new ArrayList(); actions.add(new OFActionOutput(outport, (short) 0xffff)); po.setActions(actions) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); // If the switch doens't support buffering set the buffer id to be none // otherwise it'll be the the buffer id of the PacketIn if (sw.getBuffers() == 0) { // We set the PI buffer id here so we don't have to check again below pi.setBufferId(OFPacketOut.BUFFER_ID_NONE); po.setBufferId(OFPacketOut.BUFFER_ID_NONE); } else { po.setBufferId(pi.getBufferId()); } po.setInPort(pi.getInPort()); // If the buffer id is none or the switch doesn's support buffering // we send the data with the packet out if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { byte[] packetData = pi.getPacketData(); poLength += packetData.length; po.setPacketData(packetData); } po.setLength(poLength); try { counterStore.updatePktOutFMCounterStore(sw, po); messageDamper.write(sw, po, cntx); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * Write packetout message to sw with output actions to one or more * output ports with inPort/outPorts passed in. * @param packetData * @param sw * @param inPort * @param ports * @param cntx */ public void packetOutMultiPort(byte[] packetData, IOFSwitch sw, short inPort, Set outPorts, FloodlightContext cntx) { //setting actions List actions = new ArrayList(); Iterator j = outPorts.iterator(); while (j.hasNext()) { actions.add(new OFActionOutput(j.next().shortValue(), (short) 0)); } OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_OUT); po.setActions(actions); po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * outPorts.size())); // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE po.setBufferId(OFPacketOut.BUFFER_ID_NONE); po.setInPort(inPort); // data (note buffer_id is always BUFFER_ID_NONE) and length short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); poLength += packetData.length; po.setPacketData(packetData); po.setLength(poLength); try { counterStore.updatePktOutFMCounterStore(sw, po); if (log.isTraceEnabled()) { log.trace("write broadcast packet on switch-id={} " + "interfaces={} packet-out={}", new Object[] {sw.getId(), outPorts, po}); } messageDamper.write(sw, po, cntx); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * @see packetOutMultiPort * Accepts a PacketIn instead of raw packet data. Note that the inPort * and switch can be different than the packet in switch/port */ public void packetOutMultiPort(OFPacketIn pi, IOFSwitch sw, short inPort, Set outPorts, FloodlightContext cntx) { packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx); } /** * @see packetOutMultiPort * Accepts an IPacket instead of raw packet data. Note that the inPort * and switch can be different than the packet in switch/port */ public void packetOutMultiPort(IPacket packet, IOFSwitch sw, short inPort, Set outPorts, FloodlightContext cntx) { packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx); } protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { // Get the cluster id of the switch. // Get the hash of the Ethernet packet. if (sw == null) return true; // If the feature is disabled, always return false; if (!broadcastCacheFeature) return false; Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); Long broadcastHash; broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 + pi.getInPort() * prime2 + eth.hashCode(); if (broadcastCache.update(broadcastHash)) { sw.updateBroadcastCache(broadcastHash, pi.getInPort()); return true; } else { return false; } } protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { if (sw == null) return true; // If the feature is disabled, always return false; if (!broadcastCacheFeature) return false; // Get the hash of the Ethernet packet. Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); long hash = pi.getInPort() * prime2 + eth.hashCode(); // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac return sw.updateBroadcastCache(hash, pi.getInPort()); } @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Failure writing deny flow mod", explanation="An I/O error occurred while writing a " + "deny flow mod to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) }) public static boolean blockHost(IFloodlightProviderService floodlightProvider, SwitchPort sw_tup, long host_mac, short hardTimeout, long cookie) { if (sw_tup == null) { return false; } IOFSwitch sw = floodlightProvider.getSwitches().get(sw_tup.getSwitchDPID()); if (sw == null) return false; int inputPort = sw_tup.getPort(); log.debug("blockHost sw={} port={} mac={}", new Object[] { sw, sw_tup.getPort(), new Long(host_mac) }); // Create flow-mod based on packet-in and src-switch OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory() .getMessage(OFType.FLOW_MOD); OFMatch match = new OFMatch(); List actions = new ArrayList(); // Set no action to // drop match.setDataLayerSource(Ethernet.toByteArray(host_mac)) .setInputPort((short)inputPort) .setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_IN_PORT); fm.setCookie(cookie) .setHardTimeout((short) hardTimeout) .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH); try { log.debug("write drop flow-mod sw={} match={} flow-mod={}", new Object[] { sw, match, fm }); // TODO: can't use the message damper sine this method is static sw.write(fm, null); } catch (IOException e) { log.error("Failure writing deny flow mod", e); return false; } return true; } @Override public void deviceAdded(IDevice device) { // NOOP } @Override public void deviceRemoved(IDevice device) { // NOOP } @Override public void deviceMoved(IDevice device) { } @Override public void deviceIPV4AddrChanged(IDevice device) { } @Override public void deviceVlanChanged(IDevice device) { } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return (type.equals(OFType.PACKET_IN) && (name.equals("topology") || name.equals("devicemanager"))); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } } floodlight-0.90/src/main/java/net/floodlightcontroller/forwarding/0000775000175000017500000000000012041336206026071 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java0000664000175000017500000004733712041336206031054 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.forwarding; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.routing.ForwardingBase; import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.topology.ITopologyService; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @LogMessageCategory("Flow Programming") public class Forwarding extends ForwardingBase implements IFloodlightModule { protected static Logger log = LoggerFactory.getLogger(Forwarding.class); @Override @LogMessageDoc(level="ERROR", message="Unexpected decision made for this packet-in={}", explanation="An unsupported PacketIn decision has been " + "passed to the flow programming component", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); // If a decision has been made we obey it // otherwise we just forward if (decision != null) { if (log.isTraceEnabled()) { log.trace("Forwaring decision={} was made for PacketIn={}", decision.getRoutingAction().toString(), pi); } switch(decision.getRoutingAction()) { case NONE: // don't do anything return Command.CONTINUE; case FORWARD_OR_FLOOD: case FORWARD: doForwardFlow(sw, pi, cntx, false); return Command.CONTINUE; case MULTICAST: // treat as broadcast doFlood(sw, pi, cntx); return Command.CONTINUE; case DROP: doDropFlow(sw, pi, decision, cntx); return Command.CONTINUE; default: log.error("Unexpected decision made for this packet-in={}", pi, decision.getRoutingAction()); return Command.CONTINUE; } } else { if (log.isTraceEnabled()) { log.trace("No decision was made for PacketIn={}, forwarding", pi); } if (eth.isBroadcast() || eth.isMulticast()) { // For now we treat multicast as broadcast doFlood(sw, pi, cntx); } else { doForwardFlow(sw, pi, cntx, false); } } return Command.CONTINUE; } @LogMessageDoc(level="ERROR", message="Failure writing drop flow mod", explanation="An I/O error occured while trying to write a " + "drop flow mod to a switch", recommendation=LogMessageDoc.CHECK_SWITCH) protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { // initialize match structure and populate it using the packet OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); if (decision.getWildcards() != null) { match.setWildcards(decision.getWildcards()); } // Create flow-mod based on packet-in and src-switch OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory() .getMessage(OFType.FLOW_MOD); List actions = new ArrayList(); // Set no action to // drop long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); fm.setCookie(cookie) .setHardTimeout((short) 0) .setIdleTimeout((short) 5) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH); try { if (log.isDebugEnabled()) { log.debug("write drop flow-mod sw={} match={} flow-mod={}", new Object[] { sw, match, fm }); } messageDamper.write(sw, fm, cntx); } catch (IOException e) { log.error("Failure writing drop flow mod", e); } } protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, boolean requestFlowRemovedNotifn) { OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); // Check if we have the location of the destination IDevice dstDevice = IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_DST_DEVICE); if (dstDevice != null) { IDevice srcDevice = IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); Long srcIsland = topology.getL2DomainId(sw.getId()); if (srcDevice == null) { log.debug("No device entry found for source device"); return; } if (srcIsland == null) { log.debug("No openflow island found for source {}/{}", sw.getStringId(), pi.getInPort()); return; } // Validate that we have a destination known on the same island // Validate that the source and destination are not on the same switchport boolean on_same_island = false; boolean on_same_if = false; for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { long dstSwDpid = dstDap.getSwitchDPID(); Long dstIsland = topology.getL2DomainId(dstSwDpid); if ((dstIsland != null) && dstIsland.equals(srcIsland)) { on_same_island = true; if ((sw.getId() == dstSwDpid) && (pi.getInPort() == dstDap.getPort())) { on_same_if = true; } break; } } if (!on_same_island) { // Flood since we don't know the dst device if (log.isTraceEnabled()) { log.trace("No first hop island found for destination " + "device {}, Action = flooding", dstDevice); } doFlood(sw, pi, cntx); return; } if (on_same_if) { if (log.isTraceEnabled()) { log.trace("Both source and destination are on the same " + "switch/port {}/{}, Action = NOP", sw.toString(), pi.getInPort()); } return; } // Install all the routes where both src and dst have attachment // points. Since the lists are stored in sorted order we can // traverse the attachment points in O(m+n) time SwitchPort[] srcDaps = srcDevice.getAttachmentPoints(); Arrays.sort(srcDaps, clusterIdComparator); SwitchPort[] dstDaps = dstDevice.getAttachmentPoints(); Arrays.sort(dstDaps, clusterIdComparator); int iSrcDaps = 0, iDstDaps = 0; while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { SwitchPort srcDap = srcDaps[iSrcDaps]; SwitchPort dstDap = dstDaps[iDstDaps]; Long srcCluster = topology.getL2DomainId(srcDap.getSwitchDPID()); Long dstCluster = topology.getL2DomainId(dstDap.getSwitchDPID()); int srcVsDest = srcCluster.compareTo(dstCluster); if (srcVsDest == 0) { if (!srcDap.equals(dstDap) && (srcCluster != null) && (dstCluster != null)) { Route route = routingEngine.getRoute(srcDap.getSwitchDPID(), (short)srcDap.getPort(), dstDap.getSwitchDPID(), (short)dstDap.getPort()); if (route != null) { if (log.isTraceEnabled()) { log.trace("pushRoute match={} route={} " + "destination={}:{}", new Object[] {match, route, dstDap.getSwitchDPID(), dstDap.getPort()}); } long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); // if there is prior routing decision use wildcard Integer wildcard_hints = null; IRoutingDecision decision = null; if (cntx != null) { decision = IRoutingDecision.rtStore .get(cntx, IRoutingDecision.CONTEXT_DECISION); } if (decision != null) { wildcard_hints = decision.getWildcards(); } else { // L2 only wildcard if there is no prior route decision wildcard_hints = ((Integer) sw .getAttribute(IOFSwitch.PROP_FASTWILDCARDS)) .intValue() & ~OFMatch.OFPFW_IN_PORT & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK; } pushRoute(route, match, wildcard_hints, pi, sw.getId(), cookie, cntx, requestFlowRemovedNotifn, false, OFFlowMod.OFPFC_ADD); } } iSrcDaps++; iDstDaps++; } else if (srcVsDest < 0) { iSrcDaps++; } else { iDstDaps++; } } } else { // Flood since we don't know the dst device doFlood(sw, pi, cntx); } } /** * Creates a OFPacketOut with the OFPacketIn data that is flooded on all ports unless * the port is blocked, in which case the packet will be dropped. * @param sw The switch that receives the OFPacketIn * @param pi The OFPacketIn that came to the switch * @param cntx The FloodlightContext associated with this OFPacketIn */ @LogMessageDoc(level="ERROR", message="Failure writing PacketOut " + "switch={switch} packet-in={packet-in} " + "packet-out={packet-out}", explanation="An I/O error occured while writing a packet " + "out message to the switch", recommendation=LogMessageDoc.CHECK_SWITCH) protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { if (topology.isIncomingBroadcastAllowed(sw.getId(), pi.getInPort()) == false) { if (log.isTraceEnabled()) { log.trace("doFlood, drop broadcast packet, pi={}, " + "from a blocked port, srcSwitch=[{},{}], linkInfo={}", new Object[] {pi, sw.getId(),pi.getInPort()}); } return; } // Set Action to flood OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); List actions = new ArrayList(); if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) { actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), (short)0xFFFF)); } else { actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(), (short)0xFFFF)); } po.setActions(actions); po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); // set buffer-id, in-port and packet-data based on packet-in short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); po.setBufferId(pi.getBufferId()); po.setInPort(pi.getInPort()); if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { byte[] packetData = pi.getPacketData(); poLength += packetData.length; po.setPacketData(packetData); } po.setLength(poLength); try { if (log.isTraceEnabled()) { log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}", new Object[] {sw, pi, po}); } messageDamper.write(sw, po, cntx); } catch (IOException e) { log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}", new Object[] {sw, pi, po}, e); } return; } // IFloodlightModule methods @Override public Collection> getModuleServices() { // We don't export any services return null; } @Override public Map, IFloodlightService> getServiceImpls() { // We don't have any services return null; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IDeviceService.class); l.add(IRoutingService.class); l.add(ITopologyService.class); l.add(ICounterStoreService.class); return l; } @Override @LogMessageDocs({ @LogMessageDoc(level="WARN", message="Error parsing flow idle timeout, " + "using default of {number} seconds", explanation="The properties file contains an invalid " + "flow idle timeout", recommendation="Correct the idle timeout in the " + "properties file."), @LogMessageDoc(level="WARN", message="Error parsing flow hard timeout, " + "using default of {number} seconds", explanation="The properties file contains an invalid " + "flow hard timeout", recommendation="Correct the hard timeout in the " + "properties file.") }) public void init(FloodlightModuleContext context) throws FloodlightModuleException { super.init(); this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); this.deviceManager = context.getServiceImpl(IDeviceService.class); this.routingEngine = context.getServiceImpl(IRoutingService.class); this.topology = context.getServiceImpl(ITopologyService.class); this.counterStore = context.getServiceImpl(ICounterStoreService.class); // read our config options Map configOptions = context.getConfigParams(this); try { String idleTimeout = configOptions.get("idletimeout"); if (idleTimeout != null) { FLOWMOD_DEFAULT_IDLE_TIMEOUT = Short.parseShort(idleTimeout); } } catch (NumberFormatException e) { log.warn("Error parsing flow idle timeout, " + "using default of {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT); } try { String hardTimeout = configOptions.get("hardtimeout"); if (hardTimeout != null) { FLOWMOD_DEFAULT_HARD_TIMEOUT = Short.parseShort(hardTimeout); } } catch (NumberFormatException e) { log.warn("Error parsing flow hard timeout, " + "using default of {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT); } log.debug("FlowMod idle timeout set to {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT); log.debug("FlowMod hard timeout set to {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT); } @Override public void startUp(FloodlightModuleContext context) { super.startUp(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/jython/0000775000175000017500000000000012041336206025242 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/jython/JythonServer.java0000664000175000017500000000347412041336206030557 0ustar jamespagejamespagepackage net.floodlightcontroller.jython; import java.net.URL; import java.util.HashMap; import java.util.Map; import org.python.util.PythonInterpreter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class starts a thread that runs a jython interpreter that * can be used for debug (or even development). * * @author mandeepdhami * */ public class JythonServer extends Thread { protected static Logger log = LoggerFactory.getLogger(JythonServer.class); int port; Map locals; /** * @param port_ Port to use for jython server * @param locals_ Locals to add to the interpreters top level name space */ public JythonServer(int port_, Map locals_) { this.port = port_ ; this.locals = locals_; if (this.locals == null) { this.locals = new HashMap(); } this.locals.put("log", JythonServer.log); this.setName("debugserver"); } /** * The main thread for this class invoked by Thread.run() * * @see java.lang.Thread#run() */ public void run() { PythonInterpreter p = new PythonInterpreter(); for (String name : this.locals.keySet()) { p.set(name, this.locals.get(name)); } URL jarUrl = JythonServer.class.getProtectionDomain().getCodeSource().getLocation(); String jarPath = jarUrl.getPath(); if (jarUrl.getProtocol().equals("file")) { // If URL is of type file, assume that we are in dev env and set path to python dir. // else use the jar file as is jarPath = jarPath + "../../src/main/python/"; } p.exec("import sys"); p.exec("sys.path.append('" + jarPath + "')"); p.exec("from debugserver import run_server"); p.exec("run_server(" + this.port + ", '0.0.0.0', locals())"); } } floodlight-0.90/src/main/java/net/floodlightcontroller/jython/JythonDebugInterface.java0000664000175000017500000000434412041336206032155 0ustar jamespagejamespagepackage net.floodlightcontroller.jython; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; public class JythonDebugInterface implements IFloodlightModule { protected static Logger log = LoggerFactory.getLogger(JythonDebugInterface.class); protected JythonServer debug_server; protected static int JYTHON_PORT = 6655; @Override public Collection> getModuleServices() { // We don't export services return null; } @Override public Map, IFloodlightService> getServiceImpls() { // We don't export services return null; } @Override public Collection> getModuleDependencies() { // We don't have any dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { // no-op } @Override public void startUp(FloodlightModuleContext context) { Map locals = new HashMap(); // add all existing module references to the debug server for (Class s : context.getAllServices()) { // Put only the last part of the name String[] bits = s.getCanonicalName().split("\\."); String name = bits[bits.length-1]; locals.put(name, context.getServiceImpl(s)); } // read our config options Map configOptions = context.getConfigParams(this); int port = JYTHON_PORT; String portNum = configOptions.get("port"); if (portNum != null) { port = Integer.parseInt(portNum); } JythonServer debug_server = new JythonServer(port, locals); debug_server.start(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/0000775000175000017500000000000012041336206027027 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java0000664000175000017500000000643512041336206032327 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.io.IOException; import net.floodlightcontroller.util.MACAddress; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.MappingJsonFactory; import org.restlet.data.Status; import org.restlet.resource.Delete; import org.restlet.resource.Put; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HostResource extends org.restlet.resource.ServerResource { protected static Logger log = LoggerFactory.getLogger(HostResource.class); public class HostDefinition { String port = null; // Logical port name String guid = null; // Network ID String mac = null; // MAC Address String attachment = null; // Attachment name } protected void jsonToHostDefinition(String json, HostDefinition host) throws IOException { MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(json); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; else if (n.equals("attachment")) { while (jp.nextToken() != JsonToken.END_OBJECT) { String field = jp.getCurrentName(); if (field.equals("id")) { host.attachment = jp.getText(); } else if (field.equals("mac")) { host.mac = jp.getText(); } } } } jp.close(); } @Put public String addHost(String postData) { IVirtualNetworkService vns = (IVirtualNetworkService)getContext().getAttributes(). get(IVirtualNetworkService.class.getCanonicalName()); HostDefinition host = new HostDefinition(); host.port = (String) getRequestAttributes().get("port"); host.guid = (String) getRequestAttributes().get("network"); try { jsonToHostDefinition(postData, host); } catch (IOException e) { log.error("Could not parse JSON {}", e.getMessage()); } vns.addHost(MACAddress.valueOf(host.mac), host.guid, host.port); setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; } @Delete public String deleteHost() { String port = (String) getRequestAttributes().get("port"); IVirtualNetworkService vns = (IVirtualNetworkService)getContext().getAttributes(). get(IVirtualNetworkService.class.getCanonicalName()); vns.deleteHost(null, port); setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java0000664000175000017500000001121412041336206033032 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.io.IOException; import java.util.Collection; import net.floodlightcontroller.packet.IPv4; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.MappingJsonFactory; import org.restlet.data.Status; import org.restlet.resource.Delete; import org.restlet.resource.Get; import org.restlet.resource.Post; import org.restlet.resource.Put; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NetworkResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(NetworkResource.class); public class NetworkDefinition { public String name = null; public String guid = null; public String gateway = null; } protected void jsonToNetworkDefinition(String json, NetworkDefinition network) throws IOException { MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(json); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; else if (n.equals("network")) { while (jp.nextToken() != JsonToken.END_OBJECT) { String field = jp.getCurrentName(); if (field.equals("name")) { network.name = jp.getText(); } else if (field.equals("gateway")) { String gw = jp.getText(); if ((gw != null) && (!gw.equals("null"))) network.gateway = gw; } else if (field.equals("id")) { network.guid = jp.getText(); } else { log.warn("Unrecognized field {} in " + "parsing network definition", jp.getText()); } } } } jp.close(); } @Get("json") public Collection retrieve() { IVirtualNetworkService vns = (IVirtualNetworkService)getContext().getAttributes(). get(IVirtualNetworkService.class.getCanonicalName()); return vns.listNetworks(); } @Put @Post public String createNetwork(String postData) { NetworkDefinition network = new NetworkDefinition(); try { jsonToNetworkDefinition(postData, network); } catch (IOException e) { log.error("Could not parse JSON {}", e.getMessage()); } // We try to get the ID from the URI only if it's not // in the POST data if (network.guid == null) { String guid = (String) getRequestAttributes().get("network"); if ((guid != null) && (!guid.equals("null"))) network.guid = guid; } IVirtualNetworkService vns = (IVirtualNetworkService)getContext().getAttributes(). get(IVirtualNetworkService.class.getCanonicalName()); Integer gw = null; if (network.gateway != null) { try { gw = IPv4.toIPv4Address(network.gateway); } catch (IllegalArgumentException e) { log.warn("Could not parse gateway {} as IP for network {}, setting as null", network.gateway, network.name); network.gateway = null; } } vns.createNetwork(network.guid, network.name, gw); setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; } @Delete public String deleteNetwork() { IVirtualNetworkService vns = (IVirtualNetworkService)getContext().getAttributes(). get(IVirtualNetworkService.class.getCanonicalName()); String guid = (String) getRequestAttributes().get("network"); vns.deleteNetwork(guid); setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java0000664000175000017500000000075612041336206030555 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.Post; import org.restlet.resource.Put; import org.restlet.resource.ServerResource; public class NoOp extends ServerResource { /** * Does nothing and returns 200 OK with a status message * @return status: ok */ @Get @Put @Post public String noOp(String postdata) { setStatus(Status.SUCCESS_OK); return "{\"status\":\"ok\"}"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java0000664000175000017500000000330612041336206034326 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.util.Collection; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.util.MACAddress; public interface IVirtualNetworkService extends IFloodlightService { /** * Creates a new virtual network. This can also be called * to modify a virtual network. To update a network you specify the GUID * and the fields you want to update. * @param network The network name. Must be unique. * @param guid The ID of the network. Must be unique. * @param gateway The IP address of the network gateway, null if none. */ public void createNetwork(String guid, String network, Integer gateway); /** * Deletes a virtual network. * @param guid The ID (not name) of virtual network to delete. */ public void deleteNetwork(String guid); /** * Adds a host to a virtual network. If a mapping already exists the * new one will override the old mapping. * @param mac The MAC address of the host to add. * @param network The network to add the host to. * @param port The logical port name to attach the host to. Must be unique. */ public void addHost(MACAddress mac, String network, String port); /** * Deletes a host from a virtual network. Either the MAC or Port must * be specified. * @param mac The MAC address to delete. * @param port The logical port the host is attached to. */ public void deleteHost(MACAddress mac, String port); /** * Return list of all virtual networks. * @return Collection */ public Collection listNetworks(); } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java0000664000175000017500000004633412041336206034052 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.util.HexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceListener; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.packet.DHCP; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.routing.ForwardingBase; import net.floodlightcontroller.util.MACAddress; /** * A simple Layer 2 (MAC based) network virtualization module. This module allows * you to create simple L2 networks (host + gateway) and will drop traffic if * they are not on the same virtual network. * * LIMITATIONS * - This module does not allow overlapping of IPs or MACs * - You can only have 1 gateway per virtual network (can be shared) * - There is filtering of multicast/broadcast traffic * - All DHCP traffic will be allowed, regardless of unicast/broadcast * * @author alexreimers */ public class VirtualNetworkFilter implements IFloodlightModule, IVirtualNetworkService, IOFMessageListener, IDeviceListener { protected static Logger log = LoggerFactory.getLogger(VirtualNetworkFilter.class); private final short APP_ID = 20; // Our dependencies IFloodlightProviderService floodlightProvider; IRestApiService restApi; IDeviceService deviceService; // Our internal state protected Map vNetsByGuid; // List of all created virtual networks protected Map nameToGuid; // Logical name -> Network ID protected Map guidToGateway; // Network ID -> Gateway IP protected Map> gatewayToGuid; // Gateway IP -> Network ID protected Map macToGateway; // Gateway MAC -> Gateway IP protected Map macToGuid; // Host MAC -> Network ID protected Map portToMac; // Host MAC -> logical port name /** * Adds a gateway to a virtual network. * @param guid The ID (not name) of the network. * @param ip The IP addresses of the gateway. */ protected void addGateway(String guid, Integer ip) { if (ip.intValue() != 0) { if (log.isDebugEnabled()) log.debug("Adding {} as gateway for GUID {}", IPv4.fromIPv4Address(ip), guid); guidToGateway.put(guid, ip); if (vNetsByGuid.get(guid) != null) vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(ip)); if (gatewayToGuid.containsKey(ip)) { Set gSet = gatewayToGuid.get(ip); gSet.add(guid); } else { Set gSet = Collections.synchronizedSet(new HashSet()); gSet.add(guid); gatewayToGuid.put(ip, gSet); } } } /** * Deletes a gateway for a virtual network. * @param guid The ID (not name) of the network to delete * the gateway for. */ protected void deleteGateway(String guid) { Integer gwIp = guidToGateway.remove(guid); if (gwIp == null) return; Set gSet = gatewayToGuid.get(gwIp); gSet.remove(guid); if(vNetsByGuid.get(guid)!=null) vNetsByGuid.get(guid).setGateway(null); } // IVirtualNetworkService @Override public void createNetwork(String guid, String network, Integer gateway) { if (log.isDebugEnabled()) { String gw = null; try { gw = IPv4.fromIPv4Address(gateway); } catch (Exception e) { // fail silently } log.debug("Creating network {} with ID {} and gateway {}", new Object[] {network, guid, gw}); } if (!nameToGuid.isEmpty()) { // We have to iterate all the networks to handle name/gateway changes for (Entry entry : nameToGuid.entrySet()) { if (entry.getValue().equals(guid)) { nameToGuid.remove(entry.getKey()); break; } } } nameToGuid.put(network, guid); if (vNetsByGuid.containsKey(guid)) vNetsByGuid.get(guid).setName(network); //network already exists, just updating name else vNetsByGuid.put(guid, new VirtualNetwork(network, guid)); //new network // If they don't specify a new gateway the old one will be preserved if ((gateway != null) && (gateway != 0)) { addGateway(guid, gateway); if(vNetsByGuid.get(guid)!=null) vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(gateway)); } } @Override public void deleteNetwork(String guid) { String name = null; if (nameToGuid.isEmpty()) { log.warn("Could not delete network with ID {}, network doesn't exist", guid); return; } for (Entry entry : nameToGuid.entrySet()) { if (entry.getValue().equals(guid)) { name = entry.getKey(); break; } log.warn("Could not delete network with ID {}, network doesn't exist", guid); } if (log.isDebugEnabled()) log.debug("Deleting network with name {} ID {}", name, guid); nameToGuid.remove(name); deleteGateway(guid); if(vNetsByGuid.get(guid)!=null){ vNetsByGuid.get(guid).clearHosts(); vNetsByGuid.remove(guid); } Collection deleteList = new ArrayList(); for (MACAddress host : macToGuid.keySet()) { if (macToGuid.get(host).equals(guid)) { deleteList.add(host); } } for (MACAddress mac : deleteList) { if (log.isDebugEnabled()) { log.debug("Removing host {} from network {}", HexString.toHexString(mac.toBytes()), guid); } macToGuid.remove(mac); for (Entry entry : portToMac.entrySet()) { if (entry.getValue().equals(mac)) { portToMac.remove(entry.getKey()); break; } } } } @Override public void addHost(MACAddress mac, String guid, String port) { if (guid != null) { if (log.isDebugEnabled()) { log.debug("Adding {} to network ID {} on port {}", new Object[] {mac, guid, port}); } // We ignore old mappings macToGuid.put(mac, guid); portToMac.put(port, mac); if(vNetsByGuid.get(guid)!=null) vNetsByGuid.get(guid).addHost(new MACAddress(mac.toBytes())); } else { log.warn("Could not add MAC {} to network ID {} on port {}, the network does not exist", new Object[] {mac, guid, port}); } } @Override public void deleteHost(MACAddress mac, String port) { if (log.isDebugEnabled()) { log.debug("Removing host {} from port {}", mac, port); } if (mac == null && port == null) return; if (port != null) { MACAddress host = portToMac.remove(port); if(vNetsByGuid.get(macToGuid.get(host)) != null) vNetsByGuid.get(macToGuid.get(host)).removeHost(host); macToGuid.remove(host); } else if (mac != null) { if (!portToMac.isEmpty()) { for (Entry entry : portToMac.entrySet()) { if (entry.getValue().equals(mac)) { if(vNetsByGuid.get(macToGuid.get(entry.getValue())) != null) vNetsByGuid.get(macToGuid.get(entry.getValue())).removeHost(entry.getValue()); portToMac.remove(entry.getKey()); macToGuid.remove(entry.getValue()); return; } } } } } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IVirtualNetworkService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IVirtualNetworkService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IRestApiService.class); l.add(IDeviceService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); restApi = context.getServiceImpl(IRestApiService.class); deviceService = context.getServiceImpl(IDeviceService.class); vNetsByGuid = new ConcurrentHashMap(); nameToGuid = new ConcurrentHashMap(); guidToGateway = new ConcurrentHashMap(); gatewayToGuid = new ConcurrentHashMap>(); macToGuid = new ConcurrentHashMap(); portToMac = new ConcurrentHashMap(); macToGateway = new ConcurrentHashMap(); } @Override public void startUp(FloodlightModuleContext context) { floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); restApi.addRestletRoutable(new VirtualNetworkWebRoutable()); deviceService.addListener(this); } // IOFMessageListener @Override public String getName() { return "virtualizer"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { // Link discovery should go before us so we don't block LLDPs return (type.equals(OFType.PACKET_IN) && (name.equals("linkdiscovery") || (name.equals("devicemanager")))); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { // We need to go before forwarding return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: return processPacketIn(sw, (OFPacketIn)msg, cntx); default: break; } log.warn("Received unexpected message {}", msg); return Command.CONTINUE; } /** * Checks whether the frame is destined to or from a gateway. * @param frame The ethernet frame to check. * @return True if it is to/from a gateway, false otherwise. */ protected boolean isDefaultGateway(Ethernet frame) { if (macToGateway.containsKey(frame.getSourceMAC())) return true; Integer gwIp = macToGateway.get(frame.getDestinationMAC()); if (gwIp != null) { MACAddress host = frame.getSourceMAC(); String srcNet = macToGuid.get(host); if (srcNet != null) { Integer gwIpSrcNet = guidToGateway.get(srcNet); if ((gwIpSrcNet != null) && (gwIp.equals(gwIpSrcNet))) return true; } } return false; } /** * Checks to see if two MAC Addresses are on the same network. * @param m1 The first MAC. * @param m2 The second MAC. * @return True if they are on the same virtual network, * false otherwise. */ protected boolean oneSameNetwork(MACAddress m1, MACAddress m2) { String net1 = macToGuid.get(m1); String net2 = macToGuid.get(m2); if (net1 == null) return false; if (net2 == null) return false; return net1.equals(net2); } /** * Checks to see if an Ethernet frame is a DHCP packet. * @param frame The Ethernet frame. * @return True if it is a DHCP frame, false otherwise. */ protected boolean isDhcpPacket(Ethernet frame) { IPacket payload = frame.getPayload(); // IP if (payload == null) return false; IPacket p2 = payload.getPayload(); // TCP or UDP if (p2 == null) return false; IPacket p3 = p2.getPayload(); // Application if ((p3 != null) && (p3 instanceof DHCP)) return true; return false; } /** * Processes an OFPacketIn message and decides if the OFPacketIn should be dropped * or the processing should continue. * @param sw The switch the PacketIn came from. * @param msg The OFPacketIn message from the switch. * @param cntx The FloodlightContext for this message. * @return Command.CONTINUE if processing should be continued, Command.STOP otherwise. */ protected Command processPacketIn(IOFSwitch sw, OFPacketIn msg, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); Command ret = Command.STOP; String srcNetwork = macToGuid.get(eth.getSourceMAC()); // If the host is on an unknown network we deny it. // We make exceptions for ARP and DHCP. if (eth.isBroadcast() || eth.isMulticast() || isDefaultGateway(eth) || isDhcpPacket(eth)) { ret = Command.CONTINUE; } else if (srcNetwork == null) { log.trace("Blocking traffic from host {} because it is not attached to any network.", HexString.toHexString(eth.getSourceMACAddress())); ret = Command.STOP; } else if (oneSameNetwork(eth.getSourceMAC(), eth.getDestinationMAC())) { // if they are on the same network continue ret = Command.CONTINUE; } if (log.isTraceEnabled()) log.trace("Results for flow between {} and {} is {}", new Object[] {eth.getSourceMAC(), eth.getDestinationMAC(), ret}); /* * TODO - figure out how to still detect gateways while using * drop mods if (ret == Command.STOP) { if (!(eth.getPayload() instanceof ARP)) doDropFlow(sw, msg, cntx); } */ return ret; } /** * Writes a FlowMod to a switch that inserts a drop flow. * @param sw The switch to write the FlowMod to. * @param pi The corresponding OFPacketIn. Used to create the OFMatch structure. * @param cntx The FloodlightContext that gets passed to the switch. */ protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { if (log.isTraceEnabled()) { log.trace("doDropFlow pi={} srcSwitch={}", new Object[] { pi, sw }); } if (sw == null) { log.warn("Switch is null, not installing drop flowmod for PacketIn {}", pi); return; } // Create flow-mod based on packet-in and src-switch OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); List actions = new ArrayList(); // no actions = drop long cookie = AppCookie.makeCookie(APP_ID, 0); fm.setCookie(cookie) .setIdleTimeout(ForwardingBase.FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setHardTimeout(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setMatch(match) .setActions(actions) .setLengthU(OFFlowMod.MINIMUM_LENGTH); fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM); try { if (log.isTraceEnabled()) { log.trace("write drop flow-mod srcSwitch={} match={} " + "pi={} flow-mod={}", new Object[] {sw, match, pi, fm}); } sw.write(fm, cntx); } catch (IOException e) { log.error("Failure writing drop flow mod", e); } return; } // IDeviceListener @Override public void deviceAdded(IDevice device) { if (device.getIPv4Addresses() == null) return; for (Integer i : device.getIPv4Addresses()) { if (gatewayToGuid.containsKey(i)) { MACAddress mac = MACAddress.valueOf(device.getMACAddress()); if (log.isDebugEnabled()) log.debug("Adding MAC {} with IP {} a a gateway", HexString.toHexString(mac.toBytes()), IPv4.fromIPv4Address(i)); macToGateway.put(mac, i); } } } @Override public void deviceRemoved(IDevice device) { // if device is a gateway remove MACAddress mac = MACAddress.valueOf(device.getMACAddress()); if (macToGateway.containsKey(mac)) { if (log.isDebugEnabled()) log.debug("Removing MAC {} as a gateway", HexString.toHexString(mac.toBytes())); macToGateway.remove(mac); } } @Override public void deviceIPV4AddrChanged(IDevice device) { // add or remove entry as gateway deviceAdded(device); } @Override public void deviceMoved(IDevice device) { // ignore } @Override public void deviceVlanChanged(IDevice device) { // ignore } @Override public Collection listNetworks() { return vNetsByGuid.values(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkWebRoutable.java0000664000175000017500000000161712041336206035033 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import net.floodlightcontroller.restserver.RestletRoutable; public class VirtualNetworkWebRoutable implements RestletRoutable { @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/tenants/{tenant}/networks", NetworkResource.class); // GET router.attach("/tenants/{tenant}/networks/{network}", NetworkResource.class); // PUT, DELETE router.attach("/tenants/{tenant}/networks", NetworkResource.class); // POST router.attach("/tenants/{tenant}/networks/{network}/ports/{port}/attachment", HostResource.class); router.attachDefault(NoOp.class); return router; } @Override public String basePath() { return "/quantum/v1.0"; } }floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java0000664000175000017500000000451112041336206032673 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.codehaus.jackson.map.annotate.JsonSerialize; import net.floodlightcontroller.util.MACAddress; /** * Data structure for storing and outputing information of a virtual network created * by VirtualNetworkFilter * * @author KC Wang */ @JsonSerialize(using=VirtualNetworkSerializer.class) public class VirtualNetwork{ protected String name; // network name protected String guid; // network id protected String gateway; // network gateway protected Collection hosts; // array of hosts explicitly added to this network /** * Constructor requires network name and id * @param name: network name * @param guid: network id */ public VirtualNetwork(String name, String guid) { this.name = name; this.guid = guid; this.gateway = null; this.hosts = new ArrayList(); return; } /** * Sets network name * @param gateway: IP address as String */ public void setName(String name){ this.name = name; return; } /** * Sets network gateway IP address * @param gateway: IP address as String */ public void setGateway(String gateway){ this.gateway = gateway; return; } /** * Adds a host to this network record * @param host: MAC address as MACAddress */ public void addHost(MACAddress host){ this.hosts.add(host); return; } /** * Removes a host from this network record * @param host: MAC address as MACAddress * @return boolean: true: removed, false: host not found */ public boolean removeHost(MACAddress host){ Iterator iter = this.hosts.iterator(); while(iter.hasNext()){ MACAddress element = iter.next(); if(element.equals(host) ){ //assuming MAC address for host is unique iter.remove(); return true; } } return false; } /** * Removes all hosts from this network record */ public void clearHosts(){ this.hosts.clear(); } }floodlight-0.90/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java0000664000175000017500000000216412041336206034727 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import java.io.IOException; import java.util.Iterator; import net.floodlightcontroller.util.MACAddress; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; /** * Serialize a VirtualNetwork object * @author KC Wang */ public class VirtualNetworkSerializer extends JsonSerializer { @Override public void serialize(VirtualNetwork vNet, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); jGen.writeStringField("name", vNet.name); jGen.writeStringField("guid", vNet.guid); jGen.writeStringField("gateway", vNet.gateway); jGen.writeArrayFieldStart("mac"); Iterator hit = vNet.hosts.iterator(); while (hit.hasNext()) jGen.writeString(hit.next().toString()); jGen.writeEndArray(); jGen.writeEndObject(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/hub/0000775000175000017500000000000012041336206024505 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/hub/Hub.java0000664000175000017500000001150612041336206026071 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.hub; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.util.U16; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author David Erickson (daviderickson@cs.stanford.edu) - 04/04/10 */ public class Hub implements IFloodlightModule, IOFMessageListener { protected static Logger log = LoggerFactory.getLogger(Hub.class); protected IFloodlightProviderService floodlightProvider; /** * @param floodlightProvider the floodlightProvider to set */ public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { this.floodlightProvider = floodlightProvider; } @Override public String getName() { return Hub.class.getPackage().getName(); } public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { OFPacketIn pi = (OFPacketIn) msg; OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory() .getMessage(OFType.PACKET_OUT); po.setBufferId(pi.getBufferId()) .setInPort(pi.getInPort()); // set actions OFActionOutput action = new OFActionOutput() .setPort((short) OFPort.OFPP_FLOOD.getValue()); po.setActions(Collections.singletonList((OFAction)action)); po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); // set data if is is included in the packetin if (pi.getBufferId() == 0xffffffff) { byte[] packetData = pi.getPacketData(); po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length)); po.setPacketData(packetData); } else { po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength())); } try { sw.write(po, cntx); } catch (IOException e) { log.error("Failure writing PacketOut", e); } return Command.CONTINUE; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } // IFloodlightModule @Override public Collection> getModuleServices() { // We don't provide any services, return null return null; } @Override public Map, IFloodlightService> getServiceImpls() { // We don't provide any services, return null return null; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); } @Override public void startUp(FloodlightModuleContext context) { floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/0000775000175000017500000000000012041336206025534 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/firewall/Firewall.java0000664000175000017500000007104312041336206030151 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFType; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.devicemanager.IDeviceService; import java.util.ArrayList; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.routing.RoutingDecision; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.StorageException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Stateless firewall implemented as a Google Summer of Code project. * Configuration done through REST API * * @author Amer Tahir * @edited KC Wang */ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlightModule { // service modules needed protected IFloodlightProviderService floodlightProvider; protected IStorageSourceService storageSource; protected IRestApiService restApi; protected static Logger logger; protected List rules; // protected by synchronized protected boolean enabled; protected int subnet_mask = IPv4.toIPv4Address("255.255.255.0"); // constant strings for storage/parsing public static final String TABLE_NAME = "controller_firewallrules"; public static final String COLUMN_RULEID = "ruleid"; public static final String COLUMN_DPID = "dpid"; public static final String COLUMN_IN_PORT = "in_port"; public static final String COLUMN_DL_SRC = "dl_src"; public static final String COLUMN_DL_DST = "dl_dst"; public static final String COLUMN_DL_TYPE = "dl_type"; public static final String COLUMN_NW_SRC_PREFIX = "nw_src_prefix"; public static final String COLUMN_NW_SRC_MASKBITS = "nw_src_maskbits"; public static final String COLUMN_NW_DST_PREFIX = "nw_dst_prefix"; public static final String COLUMN_NW_DST_MASKBITS = "nw_dst_maskbits"; public static final String COLUMN_NW_PROTO = "nw_proto"; public static final String COLUMN_TP_SRC = "tp_src"; public static final String COLUMN_TP_DST = "tp_dst"; public static final String COLUMN_WILDCARD_DPID = "wildcard_dpid"; public static final String COLUMN_WILDCARD_IN_PORT = "wildcard_in_port"; public static final String COLUMN_WILDCARD_DL_SRC = "wildcard_dl_src"; public static final String COLUMN_WILDCARD_DL_DST = "wildcard_dl_dst"; public static final String COLUMN_WILDCARD_DL_TYPE = "wildcard_dl_type"; public static final String COLUMN_WILDCARD_NW_SRC = "wildcard_nw_src"; public static final String COLUMN_WILDCARD_NW_DST = "wildcard_nw_dst"; public static final String COLUMN_WILDCARD_NW_PROTO = "wildcard_nw_proto"; public static final String COLUMN_WILDCARD_TP_SRC = "wildcard_tp_src"; public static final String COLUMN_WILDCARD_TP_DST = "wildcard_tp_dst"; public static final String COLUMN_PRIORITY = "priority"; public static final String COLUMN_ACTION = "action"; public static String ColumnNames[] = { COLUMN_RULEID, COLUMN_DPID, COLUMN_IN_PORT, COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_TYPE, COLUMN_NW_SRC_PREFIX, COLUMN_NW_SRC_MASKBITS, COLUMN_NW_DST_PREFIX, COLUMN_NW_DST_MASKBITS, COLUMN_NW_PROTO, COLUMN_TP_SRC, COLUMN_TP_DST, COLUMN_WILDCARD_DPID, COLUMN_WILDCARD_IN_PORT, COLUMN_WILDCARD_DL_SRC, COLUMN_WILDCARD_DL_DST, COLUMN_WILDCARD_DL_TYPE, COLUMN_WILDCARD_NW_SRC, COLUMN_WILDCARD_NW_DST, COLUMN_WILDCARD_NW_PROTO, COLUMN_PRIORITY, COLUMN_ACTION }; @Override public String getName() { return "firewall"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { // no prereq return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); } @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IFirewallService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IFirewallService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IStorageSourceService.class); l.add(IRestApiService.class); return l; } /** * Reads the rules from the storage and creates a sorted arraylist of * FirewallRule from them. * * Similar to getStorageRules(), which only reads contents for REST GET and * does no parsing, checking, nor putting into FirewallRule objects * * @return the sorted arraylist of FirewallRule instances (rules from * storage) */ protected ArrayList readRulesFromStorage() { ArrayList l = new ArrayList(); try { Map row; // (..., null, null) for no predicate, no ordering IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, ColumnNames, null, null); // put retrieved rows into FirewallRules for (Iterator it = resultSet.iterator(); it.hasNext();) { row = it.next().getRow(); // now, parse row FirewallRule r = new FirewallRule(); if (!row.containsKey(COLUMN_RULEID) || !row.containsKey(COLUMN_DPID)) { logger.error( "skipping entry with missing required 'ruleid' or 'switchid' entry: {}", row); return l; } try { r.ruleid = Integer .parseInt((String) row.get(COLUMN_RULEID)); r.dpid = Long.parseLong((String) row.get(COLUMN_DPID)); for (String key : row.keySet()) { if (row.get(key) == null) continue; if (key.equals(COLUMN_RULEID) || key.equals(COLUMN_DPID) || key.equals("id")) { continue; // already handled } else if (key.equals(COLUMN_IN_PORT)) { r.in_port = Short.parseShort((String) row .get(COLUMN_IN_PORT)); } else if (key.equals(COLUMN_DL_SRC)) { r.dl_src = Long.parseLong((String) row .get(COLUMN_DL_SRC)); } else if (key.equals(COLUMN_DL_DST)) { r.dl_dst = Long.parseLong((String) row .get(COLUMN_DL_DST)); } else if (key.equals(COLUMN_DL_TYPE)) { r.dl_type = Short.parseShort((String) row .get(COLUMN_DL_TYPE)); } else if (key.equals(COLUMN_NW_SRC_PREFIX)) { r.nw_src_prefix = Integer.parseInt((String) row .get(COLUMN_NW_SRC_PREFIX)); } else if (key.equals(COLUMN_NW_SRC_MASKBITS)) { r.nw_src_maskbits = Integer.parseInt((String) row .get(COLUMN_NW_SRC_MASKBITS)); } else if (key.equals(COLUMN_NW_DST_PREFIX)) { r.nw_dst_prefix = Integer.parseInt((String) row .get(COLUMN_NW_DST_PREFIX)); } else if (key.equals(COLUMN_NW_DST_MASKBITS)) { r.nw_dst_maskbits = Integer.parseInt((String) row .get(COLUMN_NW_DST_MASKBITS)); } else if (key.equals(COLUMN_NW_PROTO)) { r.nw_proto = Short.parseShort((String) row .get(COLUMN_NW_PROTO)); } else if (key.equals(COLUMN_TP_SRC)) { r.tp_src = Short.parseShort((String) row .get(COLUMN_TP_SRC)); } else if (key.equals(COLUMN_TP_DST)) { r.tp_dst = Short.parseShort((String) row .get(COLUMN_TP_DST)); } else if (key.equals(COLUMN_WILDCARD_DPID)) { r.wildcard_dpid = Boolean.parseBoolean((String) row .get(COLUMN_WILDCARD_DPID)); } else if (key.equals(COLUMN_WILDCARD_IN_PORT)) { r.wildcard_in_port = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_IN_PORT)); } else if (key.equals(COLUMN_WILDCARD_DL_SRC)) { r.wildcard_dl_src = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_DL_SRC)); } else if (key.equals(COLUMN_WILDCARD_DL_DST)) { r.wildcard_dl_dst = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_DL_DST)); } else if (key.equals(COLUMN_WILDCARD_DL_TYPE)) { r.wildcard_dl_type = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_DL_TYPE)); } else if (key.equals(COLUMN_WILDCARD_NW_SRC)) { r.wildcard_nw_src = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_NW_SRC)); } else if (key.equals(COLUMN_WILDCARD_NW_DST)) { r.wildcard_nw_dst = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_NW_DST)); } else if (key.equals(COLUMN_WILDCARD_NW_PROTO)) { r.wildcard_nw_proto = Boolean .parseBoolean((String) row .get(COLUMN_WILDCARD_NW_PROTO)); } else if (key.equals(COLUMN_PRIORITY)) { r.priority = Integer.parseInt((String) row .get(COLUMN_PRIORITY)); } else if (key.equals(COLUMN_ACTION)) { int tmp = Integer.parseInt((String) row.get(COLUMN_ACTION)); if (tmp == FirewallRule.FirewallAction.DENY.ordinal()) r.action = FirewallRule.FirewallAction.DENY; else if (tmp == FirewallRule.FirewallAction.ALLOW.ordinal()) r.action = FirewallRule.FirewallAction.ALLOW; else { r.action = null; logger.error("action not recognized"); } } } } catch (ClassCastException e) { logger.error( "skipping rule {} with bad data : " + e.getMessage(), r.ruleid); } if (r.action != null) l.add(r); } } catch (StorageException e) { logger.error("failed to access storage: {}", e.getMessage()); // if the table doesn't exist, then wait to populate later via // setStorageSource() } // now, sort the list based on priorities Collections.sort(l); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context .getServiceImpl(IFloodlightProviderService.class); storageSource = context.getServiceImpl(IStorageSourceService.class); restApi = context.getServiceImpl(IRestApiService.class); rules = new ArrayList(); logger = LoggerFactory.getLogger(Firewall.class); // start disabled enabled = false; } @Override public void startUp(FloodlightModuleContext context) { // register REST interface restApi.addRestletRoutable(new FirewallWebRoutable()); // always place firewall in pipeline at bootup floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); // storage, create table and read rules storageSource.createTable(TABLE_NAME, null); storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_RULEID); synchronized (rules) { this.rules = readRulesFromStorage(); } } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { if (!this.enabled) return Command.CONTINUE; switch (msg.getType()) { case PACKET_IN: IRoutingDecision decision = null; if (cntx != null) { decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx); } break; default: break; } return Command.CONTINUE; } @Override public void enableFirewall(boolean enabled) { logger.info("Setting firewall to {}", enabled); this.enabled = enabled; } @Override public List getRules() { return this.rules; } // Only used to serve REST GET // Similar to readRulesFromStorage(), which actually checks and stores // record into FirewallRule list @Override public List> getStorageRules() { ArrayList> l = new ArrayList>(); try { // null1=no predicate, null2=no ordering IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, ColumnNames, null, null); for (Iterator it = resultSet.iterator(); it.hasNext();) { l.add(it.next().getRow()); } } catch (StorageException e) { logger.error("failed to access storage: {}", e.getMessage()); // if the table doesn't exist, then wait to populate later via // setStorageSource() } return l; } @Override public String getSubnetMask() { return IPv4.fromIPv4Address(this.subnet_mask); } @Override public void setSubnetMask(String newMask) { if (newMask.trim().isEmpty()) return; this.subnet_mask = IPv4.toIPv4Address(newMask.trim()); } @Override public synchronized void addRule(FirewallRule rule) { // generate random ruleid for each newly created rule // may want to return to caller if useful // may want to check conflict rule.ruleid = rule.genID(); int i = 0; // locate the position of the new rule in the sorted arraylist for (i = 0; i < this.rules.size(); i++) { if (this.rules.get(i).priority >= rule.priority) break; } // now, add rule to the list if (i <= this.rules.size()) { this.rules.add(i, rule); } else { this.rules.add(rule); } // add rule to database Map entry = new HashMap(); entry.put(COLUMN_RULEID, Integer.toString(rule.ruleid)); entry.put(COLUMN_DPID, Long.toString(rule.dpid)); entry.put(COLUMN_IN_PORT, Short.toString(rule.in_port)); entry.put(COLUMN_DL_SRC, Long.toString(rule.dl_src)); entry.put(COLUMN_DL_DST, Long.toString(rule.dl_dst)); entry.put(COLUMN_DL_TYPE, Short.toString(rule.dl_type)); entry.put(COLUMN_NW_SRC_PREFIX, Integer.toString(rule.nw_src_prefix)); entry.put(COLUMN_NW_SRC_MASKBITS, Integer.toString(rule.nw_src_maskbits)); entry.put(COLUMN_NW_DST_PREFIX, Integer.toString(rule.nw_dst_prefix)); entry.put(COLUMN_NW_DST_MASKBITS, Integer.toString(rule.nw_dst_maskbits)); entry.put(COLUMN_NW_PROTO, Short.toString(rule.nw_proto)); entry.put(COLUMN_TP_SRC, Integer.toString(rule.tp_src)); entry.put(COLUMN_TP_DST, Integer.toString(rule.tp_dst)); entry.put(COLUMN_WILDCARD_DPID, Boolean.toString(rule.wildcard_dpid)); entry.put(COLUMN_WILDCARD_IN_PORT, Boolean.toString(rule.wildcard_in_port)); entry.put(COLUMN_WILDCARD_DL_SRC, Boolean.toString(rule.wildcard_dl_src)); entry.put(COLUMN_WILDCARD_DL_DST, Boolean.toString(rule.wildcard_dl_dst)); entry.put(COLUMN_WILDCARD_DL_TYPE, Boolean.toString(rule.wildcard_dl_type)); entry.put(COLUMN_WILDCARD_NW_SRC, Boolean.toString(rule.wildcard_nw_src)); entry.put(COLUMN_WILDCARD_NW_DST, Boolean.toString(rule.wildcard_nw_dst)); entry.put(COLUMN_WILDCARD_NW_PROTO, Boolean.toString(rule.wildcard_nw_proto)); entry.put(COLUMN_WILDCARD_TP_SRC, Boolean.toString(rule.wildcard_tp_src)); entry.put(COLUMN_WILDCARD_TP_DST, Boolean.toString(rule.wildcard_tp_dst)); entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority)); entry.put(COLUMN_ACTION, Integer.toString(rule.action.ordinal())); storageSource.insertRow(TABLE_NAME, entry); } @Override public synchronized void deleteRule(int ruleid) { Iterator iter = this.rules.iterator(); while (iter.hasNext()) { FirewallRule r = iter.next(); if (r.ruleid == ruleid) { // found the rule, now remove it iter.remove(); break; } } // delete from database storageSource.deleteRow(TABLE_NAME, Integer.toString(ruleid)); } /** * Iterates over the firewall rules and tries to match them with the * incoming packet (flow). Uses the FirewallRule class's matchWithFlow * method to perform matching. It maintains a pair of wildcards (allow and * deny) which are assigned later to the firewall's decision, where 'allow' * wildcards are applied if the matched rule turns out to be an ALLOW rule * and 'deny' wildcards are applied otherwise. Wildcards are applied to * firewall decision to optimize flows in the switch, ensuring least number * of flows per firewall rule. So, if a particular field is not "ANY" (i.e. * not wildcarded) in a higher priority rule, then if a lower priority rule * matches the packet and wildcards it, it can't be wildcarded in the * switch's flow entry, because otherwise some packets matching the higher * priority rule might escape the firewall. The reason for keeping different * two different wildcards is that if a field is not wildcarded in a higher * priority allow rule, the same field shouldn't be wildcarded for packets * matching the lower priority deny rule (non-wildcarded fields in higher * priority rules override the wildcarding of those fields in lower priority * rules of the opposite type). So, to ensure that wildcards are * appropriately set for different types of rules (allow vs. deny), separate * wildcards are maintained. Iteration is performed on the sorted list of * rules (sorted in decreasing order of priority). * * @param sw * the switch instance * @param pi * the incoming packet data structure * @param cntx * the floodlight context * @return an instance of RuleWildcardsPair that specify rule that matches * and the wildcards for the firewall decision */ protected RuleWildcardsPair matchWithRule(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { FirewallRule matched_rule = null; Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); WildcardsPair wildcards = new WildcardsPair(); synchronized (rules) { Iterator iter = this.rules.iterator(); FirewallRule rule = null; // iterate through list to find a matching firewall rule while (iter.hasNext()) { // get next rule from list rule = iter.next(); // check if rule matches if (rule.matchesFlow(sw.getId(), pi.getInPort(), eth, wildcards) == true) { matched_rule = rule; break; } } } // make a pair of rule and wildcards, then return it RuleWildcardsPair ret = new RuleWildcardsPair(); ret.rule = matched_rule; if (matched_rule == null || matched_rule.action == FirewallRule.FirewallAction.DENY) { ret.wildcards = wildcards.drop; } else { ret.wildcards = wildcards.allow; } return ret; } /** * Checks whether an IP address is a broadcast address or not (determines * using subnet mask) * * @param IPAddress * the IP address to check * @return true if it is a broadcast address, false otherwise */ protected boolean IPIsBroadcast(int IPAddress) { // inverted subnet mask int inv_subnet_mask = ~this.subnet_mask; return ((IPAddress & inv_subnet_mask) == inv_subnet_mask); } public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); // Allowing L2 broadcast + ARP broadcast request (also deny malformed // broadcasts -> L2 broadcast + L3 unicast) if (eth.isBroadcast() == true) { boolean allowBroadcast = true; // the case to determine if we have L2 broadcast + L3 unicast // don't allow this broadcast packet if such is the case (malformed // packet) if (eth.getEtherType() == Ethernet.TYPE_IPv4 && this.IPIsBroadcast(((IPv4) eth.getPayload()) .getDestinationAddress()) == false) { allowBroadcast = false; } if (allowBroadcast == true) { if (logger.isTraceEnabled()) logger.trace("Allowing broadcast traffic for PacketIn={}", pi); decision = new RoutingDecision(sw.getId(), pi.getInPort() , IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), IRoutingDecision.RoutingAction.MULTICAST); decision.addToContext(cntx); } else { if (logger.isTraceEnabled()) logger.trace( "Blocking malformed broadcast traffic for PacketIn={}", pi); decision = new RoutingDecision(sw.getId(), pi.getInPort() , IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), IRoutingDecision.RoutingAction.DROP); decision.addToContext(cntx); } return Command.CONTINUE; } /* * ARP response (unicast) can be let through without filtering through * rules by uncommenting the code below */ /* * else if (eth.getEtherType() == Ethernet.TYPE_ARP) { * logger.info("allowing ARP traffic"); decision = new * FirewallDecision(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); * decision.addToContext(cntx); return Command.CONTINUE; } */ // check if we have a matching rule for this packet/flow // and no decision is taken yet if (decision == null) { RuleWildcardsPair match_ret = this.matchWithRule(sw, pi, cntx); FirewallRule rule = match_ret.rule; if (rule == null || rule.action == FirewallRule.FirewallAction.DENY) { decision = new RoutingDecision(sw.getId(), pi.getInPort() , IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), IRoutingDecision.RoutingAction.DROP); decision.setWildcards(match_ret.wildcards); decision.addToContext(cntx); if (logger.isTraceEnabled()) { if (rule == null) logger.trace( "No firewall rule found for PacketIn={}, blocking flow", pi); else if (rule.action == FirewallRule.FirewallAction.DENY) { logger.trace("Deny rule={} match for PacketIn={}", rule, pi); } } } else { decision = new RoutingDecision(sw.getId(), pi.getInPort() , IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); decision.setWildcards(match_ret.wildcards); decision.addToContext(cntx); if (logger.isTraceEnabled()) logger.trace("Allow rule={} match for PacketIn={}", rule, pi); } } return Command.CONTINUE; } @Override public boolean isEnabled() { return enabled; } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/FirewallResource.java0000664000175000017500000001012112041336206031647 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import java.io.IOException; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.MappingJsonFactory; import org.restlet.resource.Post; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FirewallResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(FirewallResource.class); @Get("json") public Object handleRequest() { IFirewallService firewall = (IFirewallService)getContext().getAttributes(). get(IFirewallService.class.getCanonicalName()); String op = (String) getRequestAttributes().get("op"); // REST API check status if (op.equalsIgnoreCase("status")) { if (firewall.isEnabled()) return "{\"result\" : \"firewall enabled\"}"; else return "{\"result\" : \"firewall disabled\"}"; } // REST API enable firewall if (op.equalsIgnoreCase("enable")) { firewall.enableFirewall(true); return "{\"status\" : \"success\", \"details\" : \"firewall running\"}"; } // REST API disable firewall if (op.equalsIgnoreCase("disable")) { firewall.enableFirewall(false); return "{\"status\" : \"success\", \"details\" : \"firewall stopped\"}"; } // REST API retrieving rules from storage // currently equivalent to /wm/firewall/rules/json if (op.equalsIgnoreCase("storageRules")) { return firewall.getStorageRules(); } // REST API set local subnet mask -- this only makes sense for one subnet // will remove later if (op.equalsIgnoreCase("subnet-mask")) { return firewall.getSubnetMask(); } // no known options found return "{\"status\" : \"failure\", \"details\" : \"invalid operation\"}"; } /** * Allows setting of subnet mask * @param fmJson The Subnet Mask in JSON format. * @return A string status message */ @Post public String handlePost(String fmJson) { IFirewallService firewall = (IFirewallService)getContext().getAttributes(). get(IFirewallService.class.getCanonicalName()); String newMask; try { newMask = jsonExtractSubnetMask(fmJson); } catch (IOException e) { log.error("Error parsing new subnet mask: " + fmJson, e); e.printStackTrace(); return "{\"status\" : \"Error! Could not parse new subnet mask, see log for details.\"}"; } firewall.setSubnetMask(newMask); return ("{\"status\" : \"subnet mask set\"}"); } /** * Extracts subnet mask from a JSON string * @param fmJson The JSON formatted string * @return The subnet mask * @throws IOException If there was an error parsing the JSON */ public static String jsonExtractSubnetMask(String fmJson) throws IOException { String subnet_mask = ""; MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(fmJson); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; if (n == "subnet-mask") { subnet_mask = jp.getText(); break; } } return subnet_mask; } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/FirewallWebRoutable.java0000664000175000017500000000132712041336206032303 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import net.floodlightcontroller.restserver.RestletRoutable; import org.restlet.Context; import org.restlet.routing.Router; public class FirewallWebRoutable implements RestletRoutable { /** * Create the Restlet router and bind to the proper resources. */ @Override public Router getRestlet(Context context) { Router router = new Router(context); router.attach("/module/{op}/json", FirewallResource.class); router.attach("/rules/json", FirewallRulesResource.class); return router; } /** * Set the base path for the Firewall */ @Override public String basePath() { return "/wm/firewall"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java0000664000175000017500000000242512041336206031601 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.module.IFloodlightService; public interface IFirewallService extends IFloodlightService { /** * Enables/disables the firewall. * @param enable Whether to enable or disable the firewall. */ public void enableFirewall(boolean enable); /** * Returns operational status of the firewall * @return boolean enabled; */ public boolean isEnabled(); /** * Returns all of the firewall rules * @return List of all rules */ public List getRules(); /** * Returns the subnet mask * @return subnet mask */ public String getSubnetMask(); /** * Sets the subnet mask * @param newMask The new subnet mask */ public void setSubnetMask(String newMask); /** * Returns all of the firewall rules in storage * for debugging and unit-testing purposes * @return List of all rules in storage */ public List> getStorageRules(); /** * Adds a new Firewall rule */ public void addRule(FirewallRule rule); /** * Deletes a Firewall rule */ public void deleteRule(int ruleid); } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java0000664000175000017500000003663312041336206031007 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import org.openflow.protocol.OFMatch; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.TCP; import net.floodlightcontroller.packet.UDP; public class FirewallRule implements Comparable { public int ruleid; public long dpid; public short in_port; public long dl_src; public long dl_dst; public short dl_type; public int nw_src_prefix; public int nw_src_maskbits; public int nw_dst_prefix; public int nw_dst_maskbits; public short nw_proto; public short tp_src; public short tp_dst; public boolean wildcard_dpid; public boolean wildcard_in_port; public boolean wildcard_dl_src; public boolean wildcard_dl_dst; public boolean wildcard_dl_type; public boolean wildcard_nw_src; public boolean wildcard_nw_dst; public boolean wildcard_nw_proto; public boolean wildcard_tp_src; public boolean wildcard_tp_dst; public int priority = 0; public FirewallAction action; public enum FirewallAction { /* * DENY: Deny rule * ALLOW: Allow rule */ DENY, ALLOW } public FirewallRule() { this.in_port = 0; this.dl_src = 0; this.nw_src_prefix = 0; this.nw_src_maskbits = 0; this.dl_dst = 0; this.nw_proto = 0; this.tp_src = 0; this.tp_dst = 0; this.dl_dst = 0; this.nw_dst_prefix = 0; this.nw_dst_maskbits = 0; this.dpid = -1; this.wildcard_dpid = true; this.wildcard_in_port = true; this.wildcard_dl_src = true; this.wildcard_dl_dst = true; this.wildcard_dl_type = true; this.wildcard_nw_src = true; this.wildcard_nw_dst = true; this.wildcard_nw_proto = true; this.wildcard_tp_src = true; this.wildcard_tp_dst = true; this.priority = 0; this.action = FirewallAction.ALLOW; this.ruleid = 0; } /** * Generates a unique ID for the instance * * @return int representing the unique id */ public int genID() { int uid = this.hashCode(); if (uid < 0) { uid = Math.abs(uid); uid = uid * 15551; } return uid; } /** * Comparison method for Collections.sort method * * @param rule * the rule to compare with * @return number representing the result of comparison 0 if equal negative * if less than 'rule' greater than zero if greater priority rule * than 'rule' */ @Override public int compareTo(FirewallRule rule) { return this.priority - rule.priority; } /** * Determines if this instance matches an existing rule instance * * @param r * : the FirewallRule instance to compare with * @return boolean: true if a match is found **/ public boolean isSameAs(FirewallRule r) { if (this.action != r.action || this.wildcard_dl_type != r.wildcard_dl_type || (this.wildcard_dl_type == false && this.dl_type == r.dl_type) || this.wildcard_tp_src != r.wildcard_tp_src || (this.wildcard_tp_src == false && this.tp_src != r.tp_src) || this.wildcard_tp_dst != r.wildcard_tp_dst || (this.wildcard_tp_dst == false &&this.tp_dst != r.tp_dst) || this.wildcard_dpid != r.wildcard_dpid || (this.wildcard_dpid == false && this.dpid != r.dpid) || this.wildcard_in_port != r.wildcard_in_port || (this.wildcard_in_port == false && this.in_port != r.in_port) || this.wildcard_nw_src != r.wildcard_nw_src || (this.wildcard_nw_src == false && (this.nw_src_prefix != r.nw_src_prefix || this.nw_src_maskbits != r.nw_src_maskbits)) || this.wildcard_dl_src != r.wildcard_dl_src || (this.wildcard_dl_src == false && this.dl_src != r.dl_src) || this.wildcard_nw_proto != r.wildcard_nw_proto || (this.wildcard_nw_proto == false && this.nw_proto != r.nw_proto) || this.wildcard_nw_dst != r.wildcard_nw_dst || (this.wildcard_nw_dst == false && (this.nw_dst_prefix != r.nw_dst_prefix || this.nw_dst_maskbits != r.nw_dst_maskbits)) || this.wildcard_dl_dst != r.wildcard_dl_dst || (this.wildcard_dl_dst == false && this.dl_dst != r.dl_dst)) { return false; } return true; } /** * Matches this rule to a given flow - incoming packet * * @param switchDpid * the Id of the connected switch * @param inPort * the switch port where the packet originated from * @param packet * the Ethernet packet that arrives at the switch * @param wildcards * the pair of wildcards (allow and deny) given by Firewall * module that is used by the Firewall module's matchWithRule * method to derive wildcards for the decision to be taken * @return true if the rule matches the given packet-in, false otherwise */ public boolean matchesFlow(long switchDpid, short inPort, Ethernet packet, WildcardsPair wildcards) { IPacket pkt = packet.getPayload(); // dl_type type IPv4 pkt_ip = null; // nw_proto types TCP pkt_tcp = null; UDP pkt_udp = null; // tp_src and tp_dst (tp port numbers) short pkt_tp_src = 0; short pkt_tp_dst = 0; // switchID matches? if (wildcard_dpid == false && dpid != switchDpid) return false; // in_port matches? if (wildcard_in_port == false && in_port != inPort) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_IN_PORT; } else { wildcards.allow &= ~OFMatch.OFPFW_IN_PORT; } // mac address (src and dst) match? if (wildcard_dl_src == false && dl_src != packet.getSourceMAC().toLong()) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_DL_SRC; } else { wildcards.allow &= ~OFMatch.OFPFW_DL_SRC; } if (wildcard_dl_dst == false && dl_dst != packet.getDestinationMAC().toLong()) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_DL_DST; } else { wildcards.allow &= ~OFMatch.OFPFW_DL_DST; } // dl_type check: ARP, IP // if this is not an ARP rule but the pkt is ARP, // return false match - no need to continue protocol specific check if (wildcard_dl_type == false) { if (dl_type == Ethernet.TYPE_ARP) { if (packet.getEtherType() != Ethernet.TYPE_ARP) return false; else { if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; } else { wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; } } } else if (dl_type == Ethernet.TYPE_IPv4) { if (packet.getEtherType() != Ethernet.TYPE_IPv4) return false; else { if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; } else { wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; } // IP packets, proceed with ip address check pkt_ip = (IPv4) pkt; // IP addresses (src and dst) match? if (wildcard_nw_src == false && this.matchIPAddress(nw_src_prefix, nw_src_maskbits, pkt_ip.getSourceAddress()) == false) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL; wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); } else { wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL; wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); } if (wildcard_nw_dst == false && this.matchIPAddress(nw_dst_prefix, nw_dst_maskbits, pkt_ip.getDestinationAddress()) == false) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL; wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); } else { wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL; wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); } // nw_proto check if (wildcard_nw_proto == false) { if (nw_proto == IPv4.PROTOCOL_TCP) { if (pkt_ip.getProtocol() != IPv4.PROTOCOL_TCP) return false; else { pkt_tcp = (TCP) pkt_ip.getPayload(); pkt_tp_src = pkt_tcp.getSourcePort(); pkt_tp_dst = pkt_tcp.getDestinationPort(); } } else if (nw_proto == IPv4.PROTOCOL_UDP) { if (pkt_ip.getProtocol() != IPv4.PROTOCOL_UDP) return false; else { pkt_udp = (UDP) pkt_ip.getPayload(); pkt_tp_src = pkt_udp.getSourcePort(); pkt_tp_dst = pkt_udp.getDestinationPort(); } } else if (nw_proto == IPv4.PROTOCOL_ICMP) { if (pkt_ip.getProtocol() != IPv4.PROTOCOL_ICMP) return false; else { // nothing more needed for ICMP } } if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; } else { wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; } // TCP/UDP source and destination ports match? if (pkt_tcp != null || pkt_udp != null) { // does the source port match? if (tp_src != 0 && tp_src != pkt_tp_src) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_TP_SRC; } else { wildcards.allow &= ~OFMatch.OFPFW_TP_SRC; } // does the destination port match? if (tp_dst != 0 && tp_dst != pkt_tp_dst) return false; if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_TP_DST; } else { wildcards.allow &= ~OFMatch.OFPFW_TP_DST; } } } } } else { // non-IP packet - not supported - report no match return false; } } if (action == FirewallRule.FirewallAction.DENY) { wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; } else { wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; } // all applicable checks passed return true; } /** * Determines if rule's CIDR address matches IP address of the packet * * @param rulePrefix * prefix part of the CIDR address * @param ruleBits * the size of mask of the CIDR address * @param packetAddress * the IP address of the incoming packet to match with * @return true if CIDR address matches the packet's IP address, false * otherwise */ protected boolean matchIPAddress(int rulePrefix, int ruleBits, int packetAddress) { boolean matched = true; int rule_iprng = 32 - ruleBits; int rule_ipint = rulePrefix; int pkt_ipint = packetAddress; // if there's a subnet range (bits to be wildcarded > 0) if (rule_iprng > 0) { // right shift bits to remove rule_iprng of LSB that are to be // wildcarded rule_ipint = rule_ipint >> rule_iprng; pkt_ipint = pkt_ipint >> rule_iprng; // now left shift to return to normal range, except that the // rule_iprng number of LSB // are now zeroed rule_ipint = rule_ipint << rule_iprng; pkt_ipint = pkt_ipint << rule_iprng; } // check if we have a match if (rule_ipint != pkt_ipint) matched = false; return matched; } @Override public int hashCode() { final int prime = 2521; int result = super.hashCode(); result = prime * result + (int) dpid; result = prime * result + in_port; result = prime * result + (int) dl_src; result = prime * result + (int) dl_dst; result = prime * result + dl_type; result = prime * result + nw_src_prefix; result = prime * result + nw_src_maskbits; result = prime * result + nw_dst_prefix; result = prime * result + nw_dst_maskbits; result = prime * result + nw_proto; result = prime * result + tp_src; result = prime * result + tp_dst; result = prime * result + action.ordinal(); result = prime * result + priority; result = prime * result + (new Boolean(wildcard_dpid)).hashCode(); result = prime * result + (new Boolean(wildcard_in_port)).hashCode(); result = prime * result + (new Boolean(wildcard_dl_src)).hashCode(); result = prime * result + (new Boolean(wildcard_dl_dst)).hashCode(); result = prime * result + (new Boolean(wildcard_dl_type)).hashCode(); result = prime * result + (new Boolean(wildcard_nw_src)).hashCode(); result = prime * result + (new Boolean(wildcard_nw_dst)).hashCode(); result = prime * result + (new Boolean(wildcard_nw_proto)).hashCode(); result = prime * result + (new Boolean(wildcard_tp_src)).hashCode(); result = prime * result + (new Boolean(wildcard_tp_dst)).hashCode(); return result; } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java0000664000175000017500000002443612041336206032700 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import java.io.IOException; import java.util.Iterator; import java.util.List; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.MappingJsonFactory; import org.openflow.util.HexString; import org.restlet.resource.Delete; import org.restlet.resource.Post; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; public class FirewallRulesResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(FirewallRulesResource.class); @Get("json") public Object handleRequest() { IFirewallService firewall = (IFirewallService)getContext().getAttributes(). get(IFirewallService.class.getCanonicalName()); return firewall.getRules(); } /** * Takes a Firewall Rule string in JSON format and parses it into * our firewall rule data structure, then adds it to the firewall. * @param fmJson The Firewall rule entry in JSON format. * @return A string status message */ @Post public String store(String fmJson) { IFirewallService firewall = (IFirewallService)getContext().getAttributes(). get(IFirewallService.class.getCanonicalName()); FirewallRule rule; try { rule = jsonToFirewallRule(fmJson); } catch (IOException e) { log.error("Error parsing firewall rule: " + fmJson, e); e.printStackTrace(); return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}"; } String status = null; if (checkRuleExists(rule, firewall.getRules())) { status = "Error! A similar firewall rule already exists."; log.error(status); } else { // add rule to firewall firewall.addRule(rule); status = "Rule added"; } return ("{\"status\" : \"" + status + "\"}"); } /** * Takes a Firewall Rule string in JSON format and parses it into * our firewall rule data structure, then deletes it from the firewall. * @param fmJson The Firewall rule entry in JSON format. * @return A string status message */ @Delete public String remove(String fmJson) { IFirewallService firewall = (IFirewallService)getContext().getAttributes(). get(IFirewallService.class.getCanonicalName()); FirewallRule rule; try { rule = jsonToFirewallRule(fmJson); } catch (IOException e) { log.error("Error parsing firewall rule: " + fmJson, e); e.printStackTrace(); return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}"; } String status = null; boolean exists = false; Iterator iter = firewall.getRules().iterator(); while (iter.hasNext()) { FirewallRule r = iter.next(); if (r.ruleid == rule.ruleid) { exists = true; break; } } if (!exists) { status = "Error! Can't delete, a rule with this ID doesn't exist."; log.error(status); } else { // delete rule from firewall firewall.deleteRule(rule.ruleid); status = "Rule deleted"; } return ("{\"status\" : \"" + status + "\"}"); } /** * Turns a JSON formatted Firewall Rule string into a FirewallRule instance * @param fmJson The JSON formatted static firewall rule * @return The FirewallRule instance * @throws IOException If there was an error parsing the JSON */ public static FirewallRule jsonToFirewallRule(String fmJson) throws IOException { FirewallRule rule = new FirewallRule(); MappingJsonFactory f = new MappingJsonFactory(); JsonParser jp; try { jp = f.createJsonParser(fmJson); } catch (JsonParseException e) { throw new IOException(e); } jp.nextToken(); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT"); } while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME"); } String n = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; String tmp; // This is currently only applicable for remove(). In store(), ruleid takes a random number if (n == "ruleid") { rule.ruleid = Integer.parseInt((String)jp.getText()); } // This assumes user having dpid info for involved switches else if (n == "switchid") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("-1") == false) { // user inputs hex format dpid rule.dpid = HexString.toLong(tmp); rule.wildcard_dpid = false; } } else if (n == "src-inport") { rule.in_port = Short.parseShort(jp.getText()); rule.wildcard_in_port = false; } else if (n == "src-mac") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("ANY") == false) { rule.wildcard_dl_src = false; rule.dl_src = Ethernet.toLong(Ethernet.toMACAddress(tmp)); } } else if (n == "dst-mac") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("ANY") == false) { rule.wildcard_dl_dst = false; rule.dl_dst = Ethernet.toLong(Ethernet.toMACAddress(tmp)); } } else if (n == "dl-type") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("ARP")) { rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_ARP; } } else if (n == "src-ip") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("ANY") == false) { rule.wildcard_nw_src = false; rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_IPv4; int[] cidr = IPCIDRToPrefixBits(tmp); rule.nw_src_prefix = cidr[0]; rule.nw_src_maskbits = cidr[1]; } } else if (n == "dst-ip") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("ANY") == false) { rule.wildcard_nw_dst = false; rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_IPv4; int[] cidr = IPCIDRToPrefixBits(tmp); rule.nw_dst_prefix = cidr[0]; rule.nw_dst_maskbits = cidr[1]; } } else if (n == "nw-proto") { tmp = jp.getText(); if (tmp.equalsIgnoreCase("TCP")) { rule.wildcard_nw_proto = false; rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_IPv4; } else if (tmp.equalsIgnoreCase("UDP")) { rule.wildcard_nw_proto = false; rule.nw_proto = IPv4.PROTOCOL_UDP; rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_IPv4; } else if (tmp.equalsIgnoreCase("ICMP")) { rule.wildcard_nw_proto = false; rule.nw_proto = IPv4.PROTOCOL_ICMP; rule.wildcard_dl_type = false; rule.dl_type = Ethernet.TYPE_IPv4; } } else if (n == "tp-src") { rule.wildcard_tp_src = false; rule.tp_src = Short.parseShort(jp.getText()); } else if (n == "tp-dst") { rule.wildcard_tp_dst = false; rule.tp_dst = Short.parseShort(jp.getText()); } else if (n == "priority") { rule.priority = Integer.parseInt(jp.getText()); } else if (n == "action") { if (jp.getText().equalsIgnoreCase("allow") == true) { rule.action = FirewallRule.FirewallAction.ALLOW; } else if (jp.getText().equalsIgnoreCase("deny") == true) { rule.action = FirewallRule.FirewallAction.DENY; } } } return rule; } public static int[] IPCIDRToPrefixBits(String cidr) { int ret[] = new int[2]; // as IP can also be a prefix rather than an absolute address // split it over "/" to get the bit range String[] parts = cidr.split("/"); String cidr_prefix = parts[0].trim(); int cidr_bits = 0; if (parts.length == 2) { try { cidr_bits = Integer.parseInt(parts[1].trim()); } catch (Exception exp) { cidr_bits = 32; } } ret[0] = IPv4.toIPv4Address(cidr_prefix); ret[1] = cidr_bits; return ret; } public static boolean checkRuleExists(FirewallRule rule, List rules) { Iterator iter = rules.iterator(); while (iter.hasNext()) { FirewallRule r = iter.next(); // check if we find a similar rule if (rule.isSameAs(r)) { return true; } } // no rule matched, so it doesn't exist in the rules return false; } } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java0000664000175000017500000000030212041336206031752 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import org.openflow.protocol.OFMatch; public class RuleWildcardsPair { public FirewallRule rule; public int wildcards = OFMatch.OFPFW_ALL; } floodlight-0.90/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java0000664000175000017500000000030512041336206031125 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import org.openflow.protocol.OFMatch; public class WildcardsPair { public int allow = OFMatch.OFPFW_ALL; public int drop = OFMatch.OFPFW_ALL; } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/0000775000175000017500000000000012041336206025406 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/counter/CountBuffer.java0000664000175000017500000001115112041336206030472 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.counter; import java.util.Date; import net.floodlightcontroller.counter.ICounter.DateSpan; /** * Implements a circular buffer to store the last x time-based counter values. This is pretty crumby * implementation, basically wrapping everything with synchronized blocks, in order to ensure that threads * which will be updating the series don't result in a thread which is reading the series getting stuck with * a start date which does not correspond to the count values in getSeries. * * This could probably use a re-think... * * @author kyle * */ public class CountBuffer { protected long[] counterValues; protected Date startDate; protected DateSpan dateSpan; protected int currentIndex; protected int seriesLength; public CountBuffer(Date startDate, DateSpan dateSpan, int seriesLength) { this.seriesLength = seriesLength; this.counterValues = new long[seriesLength]; this.dateSpan = dateSpan; this.startDate = startDate; this.currentIndex = 0; } /** * Increment the count associated with Date d, forgetting some of the older count values if necessary to ensure * that the total span of time covered by this series corresponds to DateSpan * seriesLength (circular buffer). * * Note - fails silently if the Date falls prior to the start of the tracked count values. * * Note - this should be a reasonably fast method, though it will have to block if there is another thread reading the * series at the same time. * * @param d * @param delta */ public synchronized void increment(Date d, long delta) { long dsMillis = CountSeries.dateSpanToMilliseconds(this.dateSpan); Date endDate = new Date(startDate.getTime() + seriesLength * dsMillis - 1); if(d.getTime() < startDate.getTime()) { return; //silently fail rather than insert a count at a time older than the history buffer we're keeping } else if (d.getTime() >= startDate.getTime() && d.getTime() <= endDate.getTime()) { int index = (int) (( d.getTime() - startDate.getTime() ) / dsMillis); // java rounds down on long/long int modIndex = (index + currentIndex) % seriesLength; long currentValue = counterValues[modIndex]; counterValues[modIndex] = currentValue + delta; } else if (d.getTime() > endDate.getTime()) { //Initialize new buckets int newBuckets = (int)((d.getTime() - endDate.getTime()) / dsMillis) + 1; // java rounds down on long/long for(int i = 0; i < newBuckets; i++) { int modIndex = (i + currentIndex) % seriesLength; counterValues[modIndex] = 0; } //Update internal vars this.startDate = new Date(startDate.getTime() + dsMillis * newBuckets); this.currentIndex = (currentIndex + newBuckets) % this.seriesLength; //Call again (date should be in the range this time) this.increment(d, delta); } } /** * Relatively slow method, expected to be called primarily from UI rather than from in-packet-path. * * @return the count values associated with each time interval starting with startDate and demarc'ed by dateSpan */ public long[] getSeries() { //synchronized here should lock on 'this', implying that it shares the lock with increment long[] ret = new long[this.seriesLength]; for(int i = 0; i < this.seriesLength; i++) { int modIndex = (currentIndex + i) % this.seriesLength; ret[i] = this.counterValues[modIndex]; } return ret; } /** * Returns an immutable count series that represents a snapshot of this * series at a specific moment in time. * @return */ public synchronized CountSeries snapshot() { long[] cvs = new long[this.seriesLength]; for(int i = 0; i < this.seriesLength; i++) { int modIndex = (this.currentIndex + i) % this.seriesLength; cvs[i] = this.counterValues[modIndex]; } return new CountSeries(this.startDate, this.dateSpan, cvs); } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/ConcurrentCounter.java0000664000175000017500000001437612041336206031746 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.counter; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.counter.CounterValue.CounterType; /** * This module needs to be updated with CounterValue. * * This is a crumby attempt at a highly concurrent implementation of the Counter interface. * * (Help! Help! Someone please re-write me! This will almost certainly break at high loads.) * * The gist is that this class, ConcurrentCounter, keeps an internal highly transient buffer that is occasionally flushed * in to a set of CountBuffers (circular buffers) which store a longer term historical view of the count values at different * moments in time. * * This Counter implementation may be a bit over-engineered... The goal here was to present an implementation that is very * predictable with respect to memory and CPU time and, at the same time, present a very fast increment() method. The reasoning * here is that this will be a go-to class when it comes to debugging, particularly in high-load situations where logging * may introduce so much variability to the system that it foils the results. * * @author kyle * */ public class ConcurrentCounter implements ICounter { protected static final Map MAX_HISTORY = new HashMap(); static { MAX_HISTORY.put(DateSpan.REALTIME, new Integer(1)); MAX_HISTORY.put(DateSpan.SECONDS, new Integer(120)); MAX_HISTORY.put(DateSpan.MINUTES, new Integer(60)); MAX_HISTORY.put(DateSpan.HOURS, new Integer(48)); MAX_HISTORY.put(DateSpan.DAYS, new Integer(60)); MAX_HISTORY.put(DateSpan.WEEKS, new Integer(2)); } protected static Set liveCounters; static { liveCounters = Collections.newSetFromMap(new ConcurrentHashMap()); //nifty way to get concurrent hash set //Set a background thread to flush any liveCounters every 100 milliseconds Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { public void run() { for(ConcurrentCounter c : liveCounters) { c.flush(); } }}, 100, 100, TimeUnit.MILLISECONDS); } /** * Very simple data structure to store off a single count entry at a single point in time * @author kyle * */ protected static final class CountAtom { protected Date date; protected Long delta; protected CountAtom(Date date, Long delta) { this.date = date; this.delta = delta; } public String toString() { return "[" + this.date + ": " + this.delta + "]"; } } protected Queue unprocessedCountBuffer; protected Map counts; protected Date startDate; /** * Factory method to create a new counter instance. (Design note - * use a factory pattern here as it may be necessary to hook in other * registrations around counter objects as they are created.) * * @param startDate * @return */ public static ICounter createCounter(Date startDate) { ConcurrentCounter cc = new ConcurrentCounter(startDate); ConcurrentCounter.liveCounters.add(cc); return cc; } /** * Protected constructor - use createCounter factory method instead * @param startDate */ protected ConcurrentCounter(Date startDate) { init(startDate); } protected void init(Date startDate) { this.startDate = startDate; this.unprocessedCountBuffer = new ConcurrentLinkedQueue(); this.counts = new HashMap(); for(DateSpan ds : DateSpan.values()) { CountBuffer cb = new CountBuffer(startDate, ds, MAX_HISTORY.get(ds)); counts.put(ds, cb); } } /** * This is the key method that has to be both fast and very thread-safe. */ @Override public void increment() { this.increment(new Date(), (long)1); } @Override public void increment(Date d, long delta) { this.unprocessedCountBuffer.add(new CountAtom(d, delta)); } @Override public void setCounter(Date d, CounterValue value) { // To be done later } /** * Reset the value. */ @Override public void reset(Date startDate) { init(startDate); } /** * Flushes values out of the internal buffer and in to structures * that can be fetched with a call to snapshot() */ public synchronized void flush() { for(CountAtom c = this.unprocessedCountBuffer.poll(); c != null; c = this.unprocessedCountBuffer.poll()) { for(DateSpan ds : DateSpan.values()) { CountBuffer cb = counts.get(ds); cb.increment(c.date, c.delta); } } } @Override public CounterValue getCounterValue() { // To be done later //CountSeries cs = counts.get(DateSpan.REALTIME).snapshot(); //return cs.getSeries()[0]; return new CounterValue(CounterType.LONG); } @Override public Date getCounterDate() { // To be done later //CountSeries cs = counts.get(DateSpan.REALTIME).snapshot(); //return cs.getSeries()[0]; return new Date(); } @Override /** * This method returns a disconnected copy of the underlying CountSeries corresponding to dateSpan. */ public CountSeries snapshot(DateSpan dateSpan) { flush(); CountSeries cs = counts.get(dateSpan).snapshot(); return cs; } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/CounterValue.java0000664000175000017500000000541612041336206030673 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.counter; /** * The class defines the counter value type and value * * @author Kanzhe * */ public class CounterValue { public enum CounterType { LONG, DOUBLE } protected CounterType type; protected long longValue; protected double doubleValue; public CounterValue(CounterType type) { this.type = CounterType.LONG; this.longValue = 0; this.doubleValue = 0.0; } /** * This method is only applicable to type long. * Setter() should be used for type double */ public void increment(long delta) { if (this.type == CounterType.LONG) { this.longValue += delta; } else { throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); } } public void setLongValue(long value) { if (this.type == CounterType.LONG) { this.longValue = value; } else { throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); } } public void setDoubleValue(double value) { if (this.type == CounterType.DOUBLE) { this.doubleValue = value; } else { throw new IllegalArgumentException("Invalid counter type. This counter is not a double type."); } } public long getLong() { if (this.type == CounterType.LONG) { return this.longValue; } else { throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); } } public double getDouble() { if (this.type == CounterType.DOUBLE) { return this.doubleValue; } else { throw new IllegalArgumentException("Invalid counter type. This counter is not a double type."); } } public CounterType getType() { return this.type; } public String toString() { String ret = "{type: "; if (this.type == CounterType.DOUBLE) { ret += "Double" + ", value: " + this.doubleValue + "}"; } else { ret += "Long" + ", value: " + this.longValue + "}"; } return ret; } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/CounterStore.java0000664000175000017500000004427612041336206030722 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * Implements a very simple central store for system counters */ package net.floodlightcontroller.counter; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.CounterValue.CounterType; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author kyle * */ public class CounterStore implements IFloodlightModule, ICounterStoreService { protected static Logger log = LoggerFactory.getLogger(CounterStore.class); public enum NetworkLayer { L2, L3, L4 } protected class CounterEntry { protected ICounter counter; String title; } /** * A map of counterName --> Counter */ protected ConcurrentHashMap nameToCEIndex = new ConcurrentHashMap(); protected ICounter heartbeatCounter; protected ICounter randomCounter; /** * Counter Categories grouped by network layers * NetworkLayer -> CounterToCategories */ protected static Map>> layeredCategories = new ConcurrentHashMap>> (); public void updatePacketInCounters(IOFSwitch sw, OFMessage m, Ethernet eth) { OFPacketIn packet = (OFPacketIn)m; // Make sure there is data if (packet.getPacketData().length <= 0) return; /* Extract the etherType and protocol field for IPv4 packet. */ String etherType = String.format("%04x", eth.getEtherType()); /* * Valid EtherType must be greater than or equal to 0x0600 * It is V1 Ethernet Frame if EtherType < 0x0600 */ if (eth.getEtherType() < 0x0600) { etherType = "0599"; } if (TypeAliases.l3TypeAliasMap != null && TypeAliases.l3TypeAliasMap.containsKey(etherType)) { etherType = TypeAliases.l3TypeAliasMap.get(etherType); } else { etherType = "L3_" + etherType; } String switchIdHex = sw.getStringId(); String packetName = m.getType().toClass().getName(); packetName = packetName.substring(packetName.lastIndexOf('.')+1); // Construct controller counter for the packet_in String controllerCounterName = CounterStore.createCounterName(CONTROLLER_NAME, -1, packetName); String controllerL3CategoryCounterName = CounterStore.createCounterName(CONTROLLER_NAME, -1, packetName, etherType, NetworkLayer.L3); String l2Type = null; if (eth.isBroadcast()) { l2Type = BROADCAST; } else if (eth.isMulticast()) { l2Type = MULTICAST; } else { l2Type = UNICAST; } // Construct both port and switch L3 counter for the packet_in String controllerL2CategoryCounterName = CounterStore.createCounterName(CONTROLLER_NAME, -1, packetName, l2Type, NetworkLayer.L2); String switchL2CategoryCounterName = CounterStore.createCounterName(switchIdHex, -1, packetName, l2Type, NetworkLayer.L2); String portL2CategoryCounterName = CounterStore.createCounterName(switchIdHex, packet.getInPort(), packetName, l2Type, NetworkLayer.L2); // Construct both port and switch L3 counter for the packet_in String portCounterName = CounterStore.createCounterName(switchIdHex, packet.getInPort(), packetName); String switchCounterName = CounterStore.createCounterName(switchIdHex, -1, packetName); String portL3CategoryCounterName = CounterStore.createCounterName(switchIdHex, packet.getInPort(), packetName, etherType, NetworkLayer.L3); String switchL3CategoryCounterName = CounterStore.createCounterName(switchIdHex, -1, packetName, etherType, NetworkLayer.L3); // Controller counters ICounter controllerCounter = getCounter(controllerCounterName); if (controllerCounter == null) { controllerCounter = createCounter(controllerCounterName, CounterType.LONG); } controllerCounter.increment(); ICounter portCounter = getCounter(portCounterName); if (portCounter == null) { portCounter = createCounter(portCounterName, CounterType.LONG); } portCounter.increment(); ICounter switchCounter = getCounter(switchCounterName); if (switchCounter == null) { switchCounter = createCounter(switchCounterName, CounterType.LONG); } switchCounter.increment(); // L2 counters ICounter controllerL2Counter = getCounter(controllerL2CategoryCounterName); if (controllerL2Counter == null) { controllerL2Counter = createCounter(controllerL2CategoryCounterName, CounterType.LONG); } controllerL2Counter.increment(); ICounter switchL2Counter = getCounter(switchL2CategoryCounterName); if (switchL2Counter == null) { switchL2Counter = createCounter(switchL2CategoryCounterName, CounterType.LONG); } switchL2Counter.increment(); ICounter portL2Counter = getCounter(portL2CategoryCounterName); if (portL2Counter == null) { portL2Counter = createCounter(portL2CategoryCounterName, CounterType.LONG); } portL2Counter.increment(); // L3 counters ICounter controllerL3Counter = getCounter(controllerL3CategoryCounterName); if (controllerL3Counter == null) { controllerL3Counter = createCounter(controllerL3CategoryCounterName, CounterType.LONG); } controllerL3Counter.increment(); ICounter portL3Counter = getCounter(portL3CategoryCounterName); if (portL3Counter == null) { portL3Counter = createCounter(portL3CategoryCounterName, CounterType.LONG); } portL3Counter.increment(); ICounter switchL3Counter = getCounter(switchL3CategoryCounterName); if (switchL3Counter == null) { switchL3Counter = createCounter(switchL3CategoryCounterName, CounterType.LONG); } switchL3Counter.increment(); // L4 counters if (etherType.compareTo(CounterStore.L3ET_IPV4) == 0) { IPv4 ipV4 = (IPv4)eth.getPayload(); String l4Type = String.format("%02x", ipV4.getProtocol()); if (TypeAliases.l4TypeAliasMap != null && TypeAliases.l4TypeAliasMap.containsKey(l4Type)) { l4Type = TypeAliases.l4TypeAliasMap.get(l4Type); } else { l4Type = "L4_" + l4Type; } String controllerL4CategoryCounterName = CounterStore.createCounterName(CONTROLLER_NAME, -1, packetName, l4Type, NetworkLayer.L4); String portL4CategoryCounterName = CounterStore.createCounterName(switchIdHex, packet.getInPort(), packetName, l4Type, NetworkLayer.L4); String switchL4CategoryCounterName = CounterStore.createCounterName(switchIdHex, -1, packetName, l4Type, NetworkLayer.L4); ICounter controllerL4Counter = getCounter(controllerL4CategoryCounterName); if (controllerL4Counter == null) { controllerL4Counter = createCounter(controllerL4CategoryCounterName, CounterType.LONG); } controllerL4Counter.increment(); ICounter portL4Counter = getCounter(portL4CategoryCounterName); if (portL4Counter == null) { portL4Counter = createCounter(portL4CategoryCounterName, CounterType.LONG); } portL4Counter.increment(); ICounter switchL4Counter = getCounter(switchL4CategoryCounterName); if (switchL4Counter == null) { switchL4Counter = createCounter(switchL4CategoryCounterName, CounterType.LONG); } switchL4Counter.increment(); } } /** * This method can only be used to update packetOut and flowmod counters * * @param sw * @param ofMsg */ public void updatePktOutFMCounterStore(IOFSwitch sw, OFMessage ofMsg) { String packetName = ofMsg.getType().toClass().getName(); packetName = packetName.substring(packetName.lastIndexOf('.')+1); // flowmod is per switch and controller. portid = -1 String controllerFMCounterName = CounterStore.createCounterName(CONTROLLER_NAME, -1, packetName); ICounter counter = getCounter(controllerFMCounterName); if (counter == null) { counter = createCounter(controllerFMCounterName, CounterValue.CounterType.LONG); } counter.increment(); String switchFMCounterName = CounterStore.createCounterName(sw.getStringId(), -1, packetName); counter = getCounter(switchFMCounterName); if (counter == null) { counter = createCounter(switchFMCounterName, CounterValue.CounterType.LONG); } counter.increment(); } /** * Create a title based on switch ID, portID, vlanID, and counterName * If portID is -1, the title represents the given switch only * If portID is a non-negative number, the title represents the port on the given switch */ public static String createCounterName(String switchID, int portID, String counterName) { if (portID < 0) { return switchID + TitleDelimitor + counterName; } else { return switchID + TitleDelimitor + portID + TitleDelimitor + counterName; } } /** * Create a title based on switch ID, portID, vlanID, counterName, and subCategory * If portID is -1, the title represents the given switch only * If portID is a non-negative number, the title represents the port on the given switch * For example: PacketIns can be further categorized based on L2 etherType or L3 protocol */ public static String createCounterName(String switchID, int portID, String counterName, String subCategory, NetworkLayer layer) { String fullCounterName = ""; String groupCounterName = ""; if (portID < 0) { groupCounterName = switchID + TitleDelimitor + counterName; fullCounterName = groupCounterName + TitleDelimitor + subCategory; } else { groupCounterName = switchID + TitleDelimitor + portID + TitleDelimitor + counterName; fullCounterName = groupCounterName + TitleDelimitor + subCategory; } Map> counterToCategories; if (layeredCategories.containsKey(layer)) { counterToCategories = layeredCategories.get(layer); } else { counterToCategories = new ConcurrentHashMap> (); layeredCategories.put(layer, counterToCategories); } List categories; if (counterToCategories.containsKey(groupCounterName)) { categories = counterToCategories.get(groupCounterName); } else { categories = new ArrayList(); counterToCategories.put(groupCounterName, categories); } if (!categories.contains(subCategory)) { categories.add(subCategory); } return fullCounterName; } @Override public List getAllCategories(String counterName, NetworkLayer layer) { if (layeredCategories.containsKey(layer)) { Map> counterToCategories = layeredCategories.get(layer); if (counterToCategories.containsKey(counterName)) { return counterToCategories.get(counterName); } } return null; } @Override public ICounter createCounter(String key, CounterValue.CounterType type) { CounterEntry ce; ICounter c; c = SimpleCounter.createCounter(new Date(), type); ce = new CounterEntry(); ce.counter = c; ce.title = key; nameToCEIndex.putIfAbsent(key, ce); return nameToCEIndex.get(key).counter; } /** * Post construction init method to kick off the health check and random (test) counter threads */ @PostConstruct public void startUp() { this.heartbeatCounter = this.createCounter("CounterStore heartbeat", CounterValue.CounterType.LONG); this.randomCounter = this.createCounter("CounterStore random", CounterValue.CounterType.LONG); //Set a background thread to flush any liveCounters every 100 milliseconds Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { public void run() { heartbeatCounter.increment(); randomCounter.increment(new Date(), (long) (Math.random() * 100)); //TODO - pull this in to random timing }}, 100, 100, TimeUnit.MILLISECONDS); } @Override public ICounter getCounter(String key) { CounterEntry counter = nameToCEIndex.get(key); if (counter != null) { return counter.counter; } else { return null; } } /* (non-Javadoc) * @see net.floodlightcontroller.counter.ICounterStoreService#getAll() */ @Override public Map getAll() { Map ret = new ConcurrentHashMap(); for(Map.Entry counterEntry : this.nameToCEIndex.entrySet()) { String key = counterEntry.getKey(); ICounter counter = counterEntry.getValue().counter; ret.put(key, counter); } return ret; } @Override public Collection> getModuleServices() { Collection> services = new ArrayList>(1); services.add(ICounterStoreService.class); return services; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(ICounterStoreService.class, this); return m; } @Override public Collection> getModuleDependencies() { // no-op, no dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { // no-op for now } @Override public void startUp(FloodlightModuleContext context) { // no-op for now } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java0000664000175000017500000000602612041336206031544 0ustar jamespagejamespagepackage net.floodlightcontroller.counter; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.openflow.protocol.OFMessage; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.CounterStore.NetworkLayer; import net.floodlightcontroller.counter.CounterValue.CounterType; import net.floodlightcontroller.packet.Ethernet; /** * An ICounsterStoreService implementation that does nothing. * This is used mainly for performance testing or if you don't * want to use the counterstore. * @author alexreimers * */ public class NullCounterStore implements IFloodlightModule, ICounterStoreService { private ICounter emptyCounter; private List emptyList; private Map emptyMap; @Override public void updatePacketInCounters(IOFSwitch sw, OFMessage m, Ethernet eth) { // no-op } @Override public void updatePktOutFMCounterStore(IOFSwitch sw, OFMessage ofMsg) { // no-op } @Override public List getAllCategories(String counterName, NetworkLayer layer) { return emptyList; } @Override public ICounter createCounter(String key, CounterType type) { return emptyCounter; } @Override public ICounter getCounter(String key) { return emptyCounter; } @Override public Map getAll() { return emptyMap; } @Override public Collection> getModuleServices() { Collection> services = new ArrayList>(1); services.add(ICounterStoreService.class); return services; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(ICounterStoreService.class, this); return m; } @Override public Collection> getModuleDependencies() { // None, return null return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { emptyCounter = new SimpleCounter(new Date(), CounterType.LONG); emptyList = new ArrayList(); emptyMap = new HashMap(); } @Override public void startUp(FloodlightModuleContext context) { // no-op } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java0000664000175000017500000000714212041336206031046 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.counter; import java.util.Date; /** * This is a simple counter implementation that doesn't support data series. * The idea is that floodlight only keeps the realtime value for each counter, * statd, a statistics collection daemon, samples counters at a user-defined interval * and pushes the values to a database, which keeps time-based data series. * @author Kanzhe * */ public class SimpleCounter implements ICounter { protected CounterValue counter; protected Date samplingTime; protected Date startDate; /** * Factory method to create a new counter instance. * * @param startDate * @return */ public static ICounter createCounter(Date startDate, CounterValue.CounterType type) { SimpleCounter cc = new SimpleCounter(startDate, type); return cc; } /** * Factory method to create a copy of a counter instance. * * @param startDate * @return */ public static ICounter createCounter(ICounter copy) { if (copy == null || copy.getCounterDate() == null || copy.getCounterValue() == null) { return null; } SimpleCounter cc = new SimpleCounter(copy.getCounterDate(), copy.getCounterValue().getType()); cc.setCounter(copy.getCounterDate(), copy.getCounterValue()); return cc; } /** * Protected constructor - use createCounter factory method instead * @param startDate */ protected SimpleCounter(Date startDate, CounterValue.CounterType type) { init(startDate, type); } protected void init(Date startDate, CounterValue.CounterType type) { this.startDate = startDate; this.samplingTime = new Date(); this.counter = new CounterValue(type); } /** * This is the key method that has to be both fast and very thread-safe. */ @Override synchronized public void increment() { this.increment(new Date(), (long)1); } @Override synchronized public void increment(Date d, long delta) { this.samplingTime = d; this.counter.increment(delta); } synchronized public void setCounter(Date d, CounterValue value) { this.samplingTime = d; this.counter = value; } /** * This is the method to retrieve the current value. */ @Override synchronized public CounterValue getCounterValue() { return this.counter; } /** * This is the method to retrieve the last sampling time. */ @Override synchronized public Date getCounterDate() { return this.samplingTime; } /** * Reset value. */ @Override synchronized public void reset(Date startDate) { init(startDate, this.counter.getType()); } @Override /** * This method only returns the real-time value. */ synchronized public CountSeries snapshot(DateSpan dateSpan) { long[] values = new long[1]; values[0] = this.counter.getLong(); return new CountSeries(this.samplingTime, DateSpan.DAYS, values); } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java0000664000175000017500000000413312041336206032340 0ustar jamespagejamespagepackage net.floodlightcontroller.counter; import java.util.List; import java.util.Map; import org.openflow.protocol.OFMessage; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.CounterStore.NetworkLayer; import net.floodlightcontroller.packet.Ethernet; public interface ICounterStoreService extends IFloodlightService { public final static String CONTROLLER_NAME = "controller"; public final static String TitleDelimitor = "__"; /** Broadcast and multicast */ public final static String BROADCAST = "broadcast"; public final static String MULTICAST = "multicast"; public final static String UNICAST = "unicast"; /** L2 EtherType subCategories */ public final static String L3ET_IPV4 = "L3_IPv4"; /** * Update packetIn counters * * @param sw * @param m * @param eth */ public void updatePacketInCounters(IOFSwitch sw, OFMessage m, Ethernet eth); /** * This method can only be used to update packetOut and flowmod counters * * @param sw * @param ofMsg */ public void updatePktOutFMCounterStore(IOFSwitch sw, OFMessage ofMsg); /** * Retrieve a list of subCategories by counterName. * null if nothing. */ public List getAllCategories(String counterName, NetworkLayer layer); /** * Create a new ICounter and set the title. Note that the title must be * unique, otherwise this will throw an IllegalArgumentException. * * @param key * @param type * @return */ public ICounter createCounter(String key, CounterValue.CounterType type); /** * Retrieves a counter with the given title, or null if none can be found. */ public ICounter getCounter(String key); /** * Returns an immutable map of title:counter with all of the counters in the store. * * (Note - this method may be slow - primarily for debugging/UI) */ public Map getAll(); } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/TypeAliases.java0000664000175000017500000002057212041336206030502 0ustar jamespagejamespagepackage net.floodlightcontroller.counter; import java.util.HashMap; import java.util.Map; /** * Class to contain some statically initialized data * @author readams * */ public class TypeAliases { protected static final Map l3TypeAliasMap = new HashMap(); static { l3TypeAliasMap.put("0599", "L3_V1Ether"); l3TypeAliasMap.put("0800", "L3_IPv4"); l3TypeAliasMap.put("0806", "L3_ARP"); l3TypeAliasMap.put("8035", "L3_RARP"); l3TypeAliasMap.put("809b", "L3_AppleTalk"); l3TypeAliasMap.put("80f3", "L3_AARP"); l3TypeAliasMap.put("8100", "L3_802_1Q"); l3TypeAliasMap.put("8137", "L3_Novell_IPX"); l3TypeAliasMap.put("8138", "L3_Novell"); l3TypeAliasMap.put("86dd", "L3_IPv6"); l3TypeAliasMap.put("8847", "L3_MPLS_uni"); l3TypeAliasMap.put("8848", "L3_MPLS_multi"); l3TypeAliasMap.put("8863", "L3_PPPoE_DS"); l3TypeAliasMap.put("8864", "L3_PPPoE_SS"); l3TypeAliasMap.put("886f", "L3_MSFT_NLB"); l3TypeAliasMap.put("8870", "L3_Jumbo"); l3TypeAliasMap.put("889a", "L3_HyperSCSI"); l3TypeAliasMap.put("88a2", "L3_ATA_Ethernet"); l3TypeAliasMap.put("88a4", "L3_EtherCAT"); l3TypeAliasMap.put("88a8", "L3_802_1ad"); l3TypeAliasMap.put("88ab", "L3_Ether_Powerlink"); l3TypeAliasMap.put("88cc", "L3_LLDP"); l3TypeAliasMap.put("88cd", "L3_SERCOS_III"); l3TypeAliasMap.put("88e5", "L3_802_1ae"); l3TypeAliasMap.put("88f7", "L3_IEEE_1588"); l3TypeAliasMap.put("8902", "L3_802_1ag_CFM"); l3TypeAliasMap.put("8906", "L3_FCoE"); l3TypeAliasMap.put("9000", "L3_Loop"); l3TypeAliasMap.put("9100", "L3_Q_in_Q"); l3TypeAliasMap.put("cafe", "L3_LLT"); } protected static final Map l4TypeAliasMap = new HashMap(); static { l4TypeAliasMap.put("00", "L4_HOPOPT"); l4TypeAliasMap.put("01", "L4_ICMP"); l4TypeAliasMap.put("02", "L4_IGAP_IGMP_RGMP"); l4TypeAliasMap.put("03", "L4_GGP"); l4TypeAliasMap.put("04", "L4_IP"); l4TypeAliasMap.put("05", "L4_ST"); l4TypeAliasMap.put("06", "L4_TCP"); l4TypeAliasMap.put("07", "L4_UCL"); l4TypeAliasMap.put("08", "L4_EGP"); l4TypeAliasMap.put("09", "L4_IGRP"); l4TypeAliasMap.put("0a", "L4_BBN"); l4TypeAliasMap.put("0b", "L4_NVP"); l4TypeAliasMap.put("0c", "L4_PUP"); l4TypeAliasMap.put("0d", "L4_ARGUS"); l4TypeAliasMap.put("0e", "L4_EMCON"); l4TypeAliasMap.put("0f", "L4_XNET"); l4TypeAliasMap.put("10", "L4_Chaos"); l4TypeAliasMap.put("11", "L4_UDP"); l4TypeAliasMap.put("12", "L4_TMux"); l4TypeAliasMap.put("13", "L4_DCN"); l4TypeAliasMap.put("14", "L4_HMP"); l4TypeAliasMap.put("15", "L4_Packet_Radio"); l4TypeAliasMap.put("16", "L4_XEROX_NS_IDP"); l4TypeAliasMap.put("17", "L4_Trunk_1"); l4TypeAliasMap.put("18", "L4_Trunk_2"); l4TypeAliasMap.put("19", "L4_Leaf_1"); l4TypeAliasMap.put("1a", "L4_Leaf_2"); l4TypeAliasMap.put("1b", "L4_RDP"); l4TypeAliasMap.put("1c", "L4_IRTP"); l4TypeAliasMap.put("1d", "L4_ISO_TP4"); l4TypeAliasMap.put("1e", "L4_NETBLT"); l4TypeAliasMap.put("1f", "L4_MFE"); l4TypeAliasMap.put("20", "L4_MERIT"); l4TypeAliasMap.put("21", "L4_DCCP"); l4TypeAliasMap.put("22", "L4_Third_Party_Connect"); l4TypeAliasMap.put("23", "L4_IDPR"); l4TypeAliasMap.put("24", "L4_XTP"); l4TypeAliasMap.put("25", "L4_Datagram_Delivery"); l4TypeAliasMap.put("26", "L4_IDPR"); l4TypeAliasMap.put("27", "L4_TP"); l4TypeAliasMap.put("28", "L4_ILTP"); l4TypeAliasMap.put("29", "L4_IPv6_over_IPv4"); l4TypeAliasMap.put("2a", "L4_SDRP"); l4TypeAliasMap.put("2b", "L4_IPv6_RH"); l4TypeAliasMap.put("2c", "L4_IPv6_FH"); l4TypeAliasMap.put("2d", "L4_IDRP"); l4TypeAliasMap.put("2e", "L4_RSVP"); l4TypeAliasMap.put("2f", "L4_GRE"); l4TypeAliasMap.put("30", "L4_DSR"); l4TypeAliasMap.put("31", "L4_BNA"); l4TypeAliasMap.put("32", "L4_ESP"); l4TypeAliasMap.put("33", "L4_AH"); l4TypeAliasMap.put("34", "L4_I_NLSP"); l4TypeAliasMap.put("35", "L4_SWIPE"); l4TypeAliasMap.put("36", "L4_NARP"); l4TypeAliasMap.put("37", "L4_Minimal_Encapsulation"); l4TypeAliasMap.put("38", "L4_TLSP"); l4TypeAliasMap.put("39", "L4_SKIP"); l4TypeAliasMap.put("3a", "L4_ICMPv6"); l4TypeAliasMap.put("3b", "L4_IPv6_No_Next_Header"); l4TypeAliasMap.put("3c", "L4_IPv6_Destination_Options"); l4TypeAliasMap.put("3d", "L4_Any_host_IP"); l4TypeAliasMap.put("3e", "L4_CFTP"); l4TypeAliasMap.put("3f", "L4_Any_local"); l4TypeAliasMap.put("40", "L4_SATNET"); l4TypeAliasMap.put("41", "L4_Kryptolan"); l4TypeAliasMap.put("42", "L4_MIT_RVDP"); l4TypeAliasMap.put("43", "L4_Internet_Pluribus"); l4TypeAliasMap.put("44", "L4_Distributed_FS"); l4TypeAliasMap.put("45", "L4_SATNET"); l4TypeAliasMap.put("46", "L4_VISA"); l4TypeAliasMap.put("47", "L4_IP_Core"); l4TypeAliasMap.put("4a", "L4_Wang_Span"); l4TypeAliasMap.put("4b", "L4_Packet_Video"); l4TypeAliasMap.put("4c", "L4_Backroom_SATNET"); l4TypeAliasMap.put("4d", "L4_SUN_ND"); l4TypeAliasMap.put("4e", "L4_WIDEBAND_Monitoring"); l4TypeAliasMap.put("4f", "L4_WIDEBAND_EXPAK"); l4TypeAliasMap.put("50", "L4_ISO_IP"); l4TypeAliasMap.put("51", "L4_VMTP"); l4TypeAliasMap.put("52", "L4_SECURE_VMTP"); l4TypeAliasMap.put("53", "L4_VINES"); l4TypeAliasMap.put("54", "L4_TTP"); l4TypeAliasMap.put("55", "L4_NSFNET_IGP"); l4TypeAliasMap.put("56", "L4_Dissimilar_GP"); l4TypeAliasMap.put("57", "L4_TCF"); l4TypeAliasMap.put("58", "L4_EIGRP"); l4TypeAliasMap.put("59", "L4_OSPF"); l4TypeAliasMap.put("5a", "L4_Sprite_RPC"); l4TypeAliasMap.put("5b", "L4_Locus_ARP"); l4TypeAliasMap.put("5c", "L4_MTP"); l4TypeAliasMap.put("5d", "L4_AX"); l4TypeAliasMap.put("5e", "L4_IP_within_IP"); l4TypeAliasMap.put("5f", "L4_Mobile_ICP"); l4TypeAliasMap.put("61", "L4_EtherIP"); l4TypeAliasMap.put("62", "L4_Encapsulation_Header"); l4TypeAliasMap.put("64", "L4_GMTP"); l4TypeAliasMap.put("65", "L4_IFMP"); l4TypeAliasMap.put("66", "L4_PNNI"); l4TypeAliasMap.put("67", "L4_PIM"); l4TypeAliasMap.put("68", "L4_ARIS"); l4TypeAliasMap.put("69", "L4_SCPS"); l4TypeAliasMap.put("6a", "L4_QNX"); l4TypeAliasMap.put("6b", "L4_Active_Networks"); l4TypeAliasMap.put("6c", "L4_IPPCP"); l4TypeAliasMap.put("6d", "L4_SNP"); l4TypeAliasMap.put("6e", "L4_Compaq_Peer_Protocol"); l4TypeAliasMap.put("6f", "L4_IPX_in_IP"); l4TypeAliasMap.put("70", "L4_VRRP"); l4TypeAliasMap.put("71", "L4_PGM"); l4TypeAliasMap.put("72", "L4_0_hop"); l4TypeAliasMap.put("73", "L4_L2TP"); l4TypeAliasMap.put("74", "L4_DDX"); l4TypeAliasMap.put("75", "L4_IATP"); l4TypeAliasMap.put("76", "L4_ST"); l4TypeAliasMap.put("77", "L4_SRP"); l4TypeAliasMap.put("78", "L4_UTI"); l4TypeAliasMap.put("79", "L4_SMP"); l4TypeAliasMap.put("7a", "L4_SM"); l4TypeAliasMap.put("7b", "L4_PTP"); l4TypeAliasMap.put("7c", "L4_ISIS"); l4TypeAliasMap.put("7d", "L4_FIRE"); l4TypeAliasMap.put("7e", "L4_CRTP"); l4TypeAliasMap.put("7f", "L4_CRUDP"); l4TypeAliasMap.put("80", "L4_SSCOPMCE"); l4TypeAliasMap.put("81", "L4_IPLT"); l4TypeAliasMap.put("82", "L4_SPS"); l4TypeAliasMap.put("83", "L4_PIPE"); l4TypeAliasMap.put("84", "L4_SCTP"); l4TypeAliasMap.put("85", "L4_Fibre_Channel"); l4TypeAliasMap.put("86", "L4_RSVP_E2E_IGNORE"); l4TypeAliasMap.put("87", "L4_Mobility_Header"); l4TypeAliasMap.put("88", "L4_UDP_Lite"); l4TypeAliasMap.put("89", "L4_MPLS"); l4TypeAliasMap.put("8a", "L4_MANET"); l4TypeAliasMap.put("8b", "L4_HIP"); l4TypeAliasMap.put("8c", "L4_Shim6"); l4TypeAliasMap.put("8d", "L4_WESP"); l4TypeAliasMap.put("8e", "L4_ROHC"); } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/ICounter.java0000664000175000017500000000355512041336206030011 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * Simple interface for a counter whose value can be retrieved in several different * time increments (last x seconds, minutes, hours, days) */ package net.floodlightcontroller.counter; import java.util.Date; /** * @author kyle * */ public interface ICounter { /** * Most commonly used method */ public void increment(); /** * Used primarily for testing - no performance guarantees */ public void increment(Date d, long delta); /** * Counter value setter */ public void setCounter(Date d, CounterValue value); /** * Return the most current value */ public Date getCounterDate(); /** * Return the most current value */ public CounterValue getCounterValue(); /** * Reset the value */ public void reset(Date d); /** * Returns a CountSeries that is a snapshot of the counter's values for the given dateSpan. (Further changes * to this counter won't be reflected in the CountSeries that comes back.) * * @param dateSpan * @return */ public CountSeries snapshot(DateSpan dateSpan); public static enum DateSpan { REALTIME, SECONDS, MINUTES, HOURS, DAYS, WEEKS } } floodlight-0.90/src/main/java/net/floodlightcontroller/counter/CountSeries.java0000664000175000017500000000476312041336206030526 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.counter; import java.util.Arrays; import java.util.Date; import net.floodlightcontroller.counter.ICounter.DateSpan; /** * Simple immutable class to store a series of historic counter values * * This could probably use a re-think... * * @author kyle * */ public class CountSeries { protected long[] counterValues; protected Date startDate; protected DateSpan dateSpan; public CountSeries(Date startDate, DateSpan dateSpan, long[] counterValues) { this.counterValues = counterValues.clone(); this.dateSpan = dateSpan; this.startDate = startDate; } public long[] getSeries() { //synchronized here should lock on 'this', implying that it shares the lock with increment return this.counterValues.clone(); } /** * Returns the startDate of this series. The first long in getSeries represents the sum of deltas from increment calls with dates * that correspond to >= startDate and < startDate + DateSpan. * @return */ public Date getStartDate() {//synchronized here should lock on 'this', implying that it shares the lock with increment return this.startDate; } public String toString() { String ret = "{start: " + this.startDate + ", span: " + this.dateSpan + ", series: " + Arrays.toString(getSeries()) + "}"; return ret; } /** * Return a long that is the number of milliseconds in a ds (second/minute/hour/day/week). (Utility method.) * * @param ds * @return */ public static final long dateSpanToMilliseconds(DateSpan ds) { long delta = 1; switch(ds) { case WEEKS: delta *= 7; case DAYS: delta *= 24; case HOURS: delta *= 60; case MINUTES: delta *= 60; case SECONDS: delta *= 1000; default: break; } return delta; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/0000775000175000017500000000000012041336206024704 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/util/BundleAction.java0000664000175000017500000000326112041336206030120 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public enum BundleAction { START, STOP, UNINSTALL, REFRESH; public static List getAvailableActions(BundleState state) { List actions = new ArrayList(); if (Arrays.binarySearch(new BundleState[] { BundleState.ACTIVE, BundleState.STARTING, BundleState.UNINSTALLED }, state) < 0) { actions.add(START); } if (Arrays.binarySearch(new BundleState[] { BundleState.ACTIVE}, state) >= 0) { actions.add(STOP); } if (Arrays.binarySearch(new BundleState[] { BundleState.UNINSTALLED}, state) < 0) { actions.add(UNINSTALL); } // Always capable of refresh? actions.add(REFRESH); return actions; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/EventHistoryBaseInfoJSONSerializer.java0000664000175000017500000000432112041336206034345 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.io.IOException; import java.sql.Timestamp; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; /** * @author subrata * */ public class EventHistoryBaseInfoJSONSerializer extends JsonSerializer { /** * Performs the serialization of a EventHistory.BaseInfo object */ @Override public void serialize(EventHistoryBaseInfo base_info, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); jGen.writeNumberField("Idx", base_info.getIdx()); Timestamp ts = new Timestamp(base_info.getTime_ms()); String tsStr = ts.toString(); while (tsStr.length() < 23) { tsStr = tsStr.concat("0"); } jGen.writeStringField("Time", tsStr); jGen.writeStringField("State", base_info.getState().name()); String acStr = base_info.getAction().name().toLowerCase(); // Capitalize the first letter acStr = acStr.substring(0,1).toUpperCase().concat(acStr.substring(1)); jGen.writeStringField("Action", acStr); jGen.writeEndObject(); } /** * Tells SimpleModule that we are the serializer for OFMatch */ @Override public Class handledType() { return EventHistoryBaseInfo.class; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java0000664000175000017500000001121412041336206030510 0ustar jamespagejamespage/* * Copyright Big Switch Networks 2012 */ package net.floodlightcontroller.util; import java.io.IOException; import java.util.EnumSet; import java.util.Set; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFSwitch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; /** * Dampens OFMessages sent to an OF switch. A message is only written to * a switch if the same message (as defined by .equals()) has not been written * in the last n milliseconds. Timer granularity is based on TimedCache * @author gregor * */ public class OFMessageDamper { /** * An entry in the TimedCache. A cache entry consists of the sent message * as well as the switch to which the message was sent. * * NOTE: We currently use the full OFMessage object. To save space, we * could use a cryptographic hash (e.g., SHA-1). However, this would * obviously be more time-consuming.... * * We also store a reference to the actual IOFSwitch object and /not/ * the switch DPID. This way we are guarnteed to not dampen messages if * a switch disconnects and then reconnects. * * @author gregor */ protected static class DamperEntry { OFMessage msg; IOFSwitch sw; public DamperEntry(OFMessage msg, IOFSwitch sw) { super(); this.msg = msg; this.sw = sw; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((msg == null) ? 0 : msg.hashCode()); result = prime * result + ((sw == null) ? 0 : sw.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DamperEntry other = (DamperEntry) obj; if (msg == null) { if (other.msg != null) return false; } else if (!msg.equals(other.msg)) return false; if (sw == null) { if (other.sw != null) return false; } else if (!sw.equals(other.sw)) return false; return true; } } TimedCache cache; EnumSet msgTypesToCache; /** * * @param capacity the maximum number of messages that should be * kept * @param typesToDampen The set of OFMessageTypes that should be * dampened by this instance. Other types will be passed through * @param timeout The dampening timeout. A message will only be * written if the last write for the an equal message more than * timeout ms ago. */ public OFMessageDamper(int capacity, Set typesToDampen, int timeout) { cache = new TimedCache(capacity, timeout); msgTypesToCache = EnumSet.copyOf(typesToDampen); } /** * write the messag to the switch according to our dampening settings * @param sw * @param msg * @param cntx * @return true if the message was written to the switch, false if * the message was dampened. * @throws IOException */ public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) throws IOException { return write(sw, msg, cntx, false); } /** * write the messag to the switch according to our dampening settings * @param sw * @param msg * @param cntx * @param flush true to flush the packet immidiately * @return true if the message was written to the switch, false if * the message was dampened. * @throws IOException */ public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx, boolean flush) throws IOException { if (! msgTypesToCache.contains(msg.getType())) { sw.write(msg, cntx); if (flush) { sw.flush(); } return true; } DamperEntry entry = new DamperEntry(msg, sw); if (cache.update(entry)) { // entry exists in cache. Dampening. return false; } else { sw.write(msg, cntx); if (flush) { sw.flush(); } return true; } } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/EventHistory.java0000664000175000017500000001241312041336206030213 0ustar jamespagejamespage/** * */ package net.floodlightcontroller.util; import java.util.ArrayList; /** * @author subrata * */ public class EventHistory { public static final int EV_HISTORY_DEFAULT_SIZE = 1024; public String description; public int event_history_size; public int current_index; public boolean full; // true if all are in use public ArrayList events; public String getDescription() { return description; } public int getEvent_history_size() { return event_history_size; } public int getCurrent_index() { return current_index; } public boolean isFull() { return full; } public ArrayList getEvents() { return events; } public class Event { public EventHistoryBaseInfo base_info; public T info; } public enum EvState { FREE, // no valid event written yet BEING_MODIFIED, // event is being updated with new value, skip ACTIVE, // event is active and can be displayed } public enum EvAction { ADDED, // specific entry added REMOVED, // specific entry removed UPDATED, // Entry updated BLOCKED, // Blocked - used for Attachment Points UNBLOCKED, CLEARED, // All entries are removed PKT_IN, PKT_OUT, SWITCH_CONNECTED, SWITCH_DISCONNECTED, LINK_ADDED, LINK_DELETED, LINK_PORT_STATE_UPDATED, CLUSTER_ID_CHANGED_FOR_CLUSTER, CLUSTER_ID_CHANGED_FOR_A_SWITCH, } // Constructor public EventHistory(int maxEvents, String desc) { events = new ArrayList(maxEvents); for (int idx = 0; idx < maxEvents; idx++) { Event evH = new Event(); evH.base_info = new EventHistoryBaseInfo(); evH.info = null; evH.base_info.state = EvState.FREE; evH.base_info.idx = idx; events.add(idx, evH); } description = "Event-History:" + desc; event_history_size = maxEvents; current_index = 0; full = false; } // Constructor for default size public EventHistory(String desc) { this(EV_HISTORY_DEFAULT_SIZE, desc); } // Copy constructor - copy latest k items of the event history public EventHistory(EventHistory eventHist, int latestK) { if (eventHist == null) { description = "No event found"; return; } int curSize = (eventHist.full)?eventHist.event_history_size: eventHist.current_index; int size = (latestK < curSize)?latestK:curSize; int evIdx = eventHist.current_index; int topSz = (evIdx >= size)?size:evIdx; // Need to create a new one since size is different events = new ArrayList(size); // Get the top part int origIdx = evIdx; for (int idx = 0; idx < topSz; idx++) { Event evH = eventHist.events.get(--origIdx); evH.base_info.idx = idx; events.add(idx, evH); } // Get the bottom part origIdx = eventHist.event_history_size; for (int idx = topSz; idx < size; idx++) { Event evH = eventHist.events.get(--origIdx); evH.base_info.idx = idx; events.add(idx, evH); } description = eventHist.description; event_history_size = size; current_index = 0; // since it is full full = true; } // Get an index for writing a new event. This method is synchronized for // this event history infra. to be thread-safe. Once the index is obtained // by the caller event at the index is updated without any lock public synchronized int NextIdx() { // curIdx should be in the 0 to evArraySz-1 if (current_index == (event_history_size-1)) { current_index = 0; full = true; return (event_history_size-1); } else { current_index++; return (current_index-1); } } /** * Add an event to the event history * Eliminate java garbage cration by reusing the same object T * Supplied object t is used to populate the event history array * and the current object at that array location is returned to the * calling process so that the calling process can use that object * for the next event of the same type * @param t * @param op * @return */ public T put(T t, EvAction action) { int idx = NextIdx(); Event evH = events.get(idx); evH.base_info.state = EvState.BEING_MODIFIED; evH.base_info.time_ms = System.currentTimeMillis(); evH.base_info.action = action; T temp = evH.info; evH.info = t; evH.base_info.state = EvState.ACTIVE; return temp; } /*** * Clear the event history, needs to be done under lock */ public void clear() { for (int idx = 0; idx < event_history_size; idx++) { Event evH = events.get(idx); evH.base_info.state = EvState.FREE; current_index = 0; full = false; } } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/MultiIterator.java0000664000175000017500000000353112041336206030355 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.util.Iterator; import java.util.NoSuchElementException; /** * Iterator over all values in an iterator of iterators * * @param the type of elements returned by this iterator */ public class MultiIterator implements Iterator { Iterator> subIterator; Iterator current = null; public MultiIterator(Iterator> subIterator) { super(); this.subIterator = subIterator; } @Override public boolean hasNext() { if (current == null) { if (subIterator.hasNext()) { current = subIterator.next(); } else { return false; } } while (!current.hasNext() && subIterator.hasNext()) { current = subIterator.next(); } return current.hasNext(); } @Override public T next() { if (hasNext()) return current.next(); throw new NoSuchElementException(); } @Override public void remove() { if (hasNext()) current.remove(); throw new NoSuchElementException(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/IterableIterator.java0000664000175000017500000000361112041336206031011 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.util.Iterator; import java.util.NoSuchElementException; /** * Iterator over all values in an iterator of iterators * * @param the type of elements returned by this iterator */ public class IterableIterator implements Iterator { Iterator> subIterator; Iterator current = null; public IterableIterator(Iterator> subIterator) { super(); this.subIterator = subIterator; } @Override public boolean hasNext() { if (current == null) { if (subIterator.hasNext()) { current = subIterator.next().iterator(); } else { return false; } } while (!current.hasNext() && subIterator.hasNext()) { current = subIterator.next().iterator(); } return current.hasNext(); } @Override public T next() { if (hasNext()) return current.next(); throw new NoSuchElementException(); } @Override public void remove() { if (hasNext()) current.remove(); throw new NoSuchElementException(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/ClusterDFS.java0000664000175000017500000000167412041336206027535 0ustar jamespagejamespagepackage net.floodlightcontroller.util; public class ClusterDFS { long dfsIndex; long parentDFSIndex; long lowpoint; boolean visited; public ClusterDFS() { visited = false; dfsIndex = Long.MAX_VALUE; parentDFSIndex = Long.MAX_VALUE; lowpoint = Long.MAX_VALUE; } public long getDfsIndex() { return dfsIndex; } public void setDfsIndex(long dfsIndex) { this.dfsIndex = dfsIndex; } public long getParentDFSIndex() { return parentDFSIndex; } public void setParentDFSIndex(long parentDFSIndex) { this.parentDFSIndex = parentDFSIndex; } public long getLowpoint() { return lowpoint; } public void setLowpoint(long lowpoint) { this.lowpoint = lowpoint; } public boolean isVisited() { return visited; } public void setVisited(boolean visited) { this.visited = visited; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/EventHistoryBaseInfo.java0000664000175000017500000000124012041336206031616 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import org.codehaus.jackson.map.annotate.JsonSerialize; @JsonSerialize(using=EventHistoryBaseInfoJSONSerializer.class) public class EventHistoryBaseInfo { public int idx; public long time_ms; // timestamp in milliseconds public EventHistory.EvState state; public EventHistory.EvAction action; // Getters public int getIdx() { return idx; } public long getTime_ms() { return time_ms; } public EventHistory.EvState getState() { return state; } public EventHistory.EvAction getAction() { return action; } }floodlight-0.90/src/main/java/net/floodlightcontroller/util/TimedCache.java0000664000175000017500000000504112041336206027535 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; import java.util.concurrent.ConcurrentMap; /** * The key is any object/hash-code * The value is time-stamp in milliseconds * The time interval denotes the interval for which the entry should remain in the hashmap. * If an entry is present in the Linkedhashmap, it does not mean that it's valid (recently seen) * * @param Type of the values in this cache */ public class TimedCache { private final long timeoutInterval; //specified in milliseconds. private ConcurrentMap cache; /** * * @param capacity the maximum number of entries in the cache before the * oldest entry is evicted. * @param timeToLive specified in milliseconds */ public TimedCache(int capacity, int timeToLive) { cache = new ConcurrentLinkedHashMap.Builder() .maximumWeightedCapacity(capacity) .build(); this.timeoutInterval = timeToLive; } public long getTimeoutInterval() { return this.timeoutInterval; } /** * Always try to update the cache and set the last-seen value for this key. * * Return true, if a valid existing field was updated, else return false. * (note: if multiple threads update simultaneously, one of them will succeed, * other wills return false) * * @param key * @return boolean */ public boolean update(K key) { Long curr = new Long(System.currentTimeMillis()); Long prev = cache.putIfAbsent(key, curr); if (prev == null) { return false; } if (curr - prev > this.timeoutInterval) { if (cache.replace(key, prev, curr)) { return false; } } return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/MACAddress.java0000664000175000017500000001206112041336206027455 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import java.util.Arrays; /** * The class representing MAC address. * * @author Sho Shimizu (sho.shimizu@gmail.com) */ public class MACAddress { public static final int MAC_ADDRESS_LENGTH = 6; private byte[] address = new byte[MAC_ADDRESS_LENGTH]; public MACAddress(byte[] address) { this.address = Arrays.copyOf(address, MAC_ADDRESS_LENGTH); } /** * Returns a MAC address instance representing the value of the specified {@code String}. * @param address the String representation of the MAC Address to be parsed. * @return a MAC Address instance representing the value of the specified {@code String}. * @throws IllegalArgumentException if the string cannot be parsed as a MAC address. */ public static MACAddress valueOf(String address) { String[] elements = address.split(":"); if (elements.length != MAC_ADDRESS_LENGTH) { throw new IllegalArgumentException( "Specified MAC Address must contain 12 hex digits" + " separated pairwise by :'s."); } byte[] addressInBytes = new byte[MAC_ADDRESS_LENGTH]; for (int i = 0; i < MAC_ADDRESS_LENGTH; i++) { String element = elements[i]; addressInBytes[i] = (byte)Integer.parseInt(element, 16); } return new MACAddress(addressInBytes); } /** * Returns a MAC address instance representing the specified {@code byte} array. * @param address the byte array to be parsed. * @return a MAC address instance representing the specified {@code byte} array. * @throws IllegalArgumentException if the byte array cannot be parsed as a MAC address. */ public static MACAddress valueOf(byte[] address) { if (address.length != MAC_ADDRESS_LENGTH) { throw new IllegalArgumentException("the length is not " + MAC_ADDRESS_LENGTH); } return new MACAddress(address); } /** * Returns a MAC address instance representing the specified {@code long} value. * The lower 48 bits of the long value are used to parse as a MAC address. * @param address the long value to be parsed. The lower 48 bits are used for a MAC address. * @return a MAC address instance representing the specified {@code long} value. * @throws IllegalArgumentException if the long value cannot be parsed as a MAC address. */ public static MACAddress valueOf(long address) { byte[] addressInBytes = new byte[] { (byte)((address >> 40) & 0xff), (byte)((address >> 32) & 0xff), (byte)((address >> 24) & 0xff), (byte)((address >> 16) & 0xff), (byte)((address >> 8 ) & 0xff), (byte)((address >> 0) & 0xff) }; return new MACAddress(addressInBytes); } /** * Returns the length of the {@code MACAddress}. * @return the length of the {@code MACAddress}. */ public int length() { return address.length; } /** * Returns the value of the {@code MACAddress} as a {@code byte} array. * @return the numeric value represented by this object after conversion to type {@code byte} array. */ public byte[] toBytes() { return Arrays.copyOf(address, address.length); } /** * Returns the value of the {@code MACAddress} as a {@code long}. * @return the numeric value represented by this object after conversion to type {@code long}. */ public long toLong() { long mac = 0; for (int i = 0; i < 6; i++) { long t = (address[i] & 0xffL) << ((5 - i) * 8); mac |= t; } return mac; } /** * Returns {@code true} if the MAC address is the broadcast address. * @return {@code true} if the MAC address is the broadcast address. */ public boolean isBroadcast() { for (byte b : address) { if (b != -1) // checks if equal to 0xff return false; } return true; } /** * Returns {@code true} if the MAC address is the multicast address. * @return {@code true} if the MAC address is the multicast address. */ public boolean isMulticast() { if (isBroadcast()) { return false; } return (address[0] & 0x01) != 0; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof MACAddress)) { return false; } MACAddress other = (MACAddress)o; return Arrays.equals(this.address, other.address); } @Override public int hashCode() { return Arrays.hashCode(this.address); } @Override public String toString() { StringBuilder builder = new StringBuilder(); for (byte b: address) { if (builder.length() > 0) { builder.append(":"); } builder.append(String.format("%02X", b & 0xFF)); } return builder.toString(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/FilterIterator.java0000664000175000017500000000423212041336206030507 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.util.Iterator; import java.util.NoSuchElementException; /** * An iterator that will filter values from an iterator and return only * those values that match the predicate. */ public abstract class FilterIterator implements Iterator { protected Iterator subIterator; protected T next; /** * Construct a filter iterator from the given sub iterator * @param subIterator the sub iterator over which we'll filter */ public FilterIterator(Iterator subIterator) { super(); this.subIterator = subIterator; } /** * Check whether the given value should be returned by the * filter * @param value the value to check * @return true if the value should be included */ protected abstract boolean matches(T value); // *********** // Iterator // *********** @Override public boolean hasNext() { if (next != null) return true; while (subIterator.hasNext()) { next = subIterator.next(); if (matches(next)) return true; } next = null; return false; } @Override public T next() { if (hasNext()) { T cur = next; next = null; return cur; } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/LRUHashMap.java0000664000175000017500000000223312041336206027453 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; import java.util.LinkedHashMap; import java.util.Map; public class LRUHashMap extends LinkedHashMap { private static final long serialVersionUID = 1L; private final int capacity; public LRUHashMap(int capacity) { super(capacity+1, 0.75f, true); this.capacity = capacity; } protected boolean removeEldestEntry(Map.Entry eldest) { return size() > capacity; } } floodlight-0.90/src/main/java/net/floodlightcontroller/util/BundleState.java0000664000175000017500000000315112041336206027761 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.util; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public enum BundleState { ACTIVE (32), INSTALLED (2), RESOLVED (4), STARTING (8), STOPPING (16), UNINSTALLED (1); protected int value; private BundleState(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } public static BundleState getState(int value) { switch (value) { case 32: return ACTIVE; case 2: return INSTALLED; case 4: return RESOLVED; case 8: return STARTING; case 16: return STOPPING; case 1: return UNINSTALLED; } return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/0000775000175000017500000000000012041336206025375 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/PerfMonToggleResource.java0000664000175000017500000000203712041336206032462 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class PerfMonToggleResource extends ServerResource { @Get("json") public String retrieve() { IPktInProcessingTimeService pktinProcTime = (IPktInProcessingTimeService)getContext().getAttributes(). get(IPktInProcessingTimeService.class.getCanonicalName()); String param = ((String)getRequestAttributes().get("perfmonstate")).toLowerCase(); if (param.equals("reset")) { pktinProcTime.getCtb().reset(); } else { if (param.equals("enable") || param.equals("true")) { pktinProcTime.setEnabled(true); } else if (param.equals("disable") || param.equals("false")) { pktinProcTime.setEnabled(false); } } setStatus(Status.SUCCESS_OK, "OK"); return "{ \"enabled\" : " + pktinProcTime.isEnabled() + " }"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java0000664000175000017500000000225612041336206033600 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import java.util.List; import org.openflow.protocol.OFMessage; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.IFloodlightService; public interface IPktInProcessingTimeService extends IFloodlightService { /** * Creates time buckets for a set of modules to measure their performance * @param listeners The message listeners to create time buckets for */ public void bootstrap(List listeners); /** * Stores a timestamp in ns. Used right before a service handles an * OF message. Only stores if the service is enabled. */ public void recordStartTimeComp(IOFMessageListener listener); public void recordEndTimeComp(IOFMessageListener listener); public void recordStartTimePktIn(); public void recordEndTimePktIn(IOFSwitch sw, OFMessage m, FloodlightContext cntx); public boolean isEnabled(); public void setEnabled(boolean enabled); public CumulativeTimeBucket getCtb(); } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java0000664000175000017500000001620512041336206032145 0ustar jamespagejamespage/** * Performance monitoring package */ package net.floodlightcontroller.perfmon; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.restserver.IRestApiService; import org.openflow.protocol.OFMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class contains a set of buckets (called time buckets as the * primarily contain 'times' that are used in a circular way to * store information on packet in processing time. * Each bucket is meant to store the various processing time * related data for a fixed duration. * Buckets are reused to reduce garbage generation! Once the * last bucket is used up the LRU bucket is reused. * * Naming convention for variable or constants * variable_s : value in seconds * variable_ms: value in milliseconds * variable_us: value in microseconds * variable_ns: value in nanoseconds * * Key Constants: * ONE_BUCKET_DURATION_SECONDS_INT: time duration of each bucket * BUCKET_SET_SIZE: Number of buckets * TOT_PROC_TIME_WARN_THRESHOLD_US: if processing time for a packet * exceeds this threshold then a warning LOG message is generated * TOT_PROC_TIME_ALERT_THRESHOLD_US: same as above but an alert level * syslog is generated instead * */ @LogMessageCategory("Performance Monitoring") public class PktInProcessingTime implements IFloodlightModule, IPktInProcessingTimeService { // Our dependencies private IRestApiService restApi; protected long ptWarningThresholdInNano; // DB storage tables protected static final String ControllerTableName = "controller_controller"; public static final String COLUMN_ID = "id"; public static final String COLUMN_PERF_MON = "performance_monitor_feature"; protected static Logger logger = LoggerFactory.getLogger(PktInProcessingTime.class); protected boolean isEnabled = false; protected boolean isInited = false; // Maintains the time when the last packet was processed protected long lastPktTime_ns; private CumulativeTimeBucket ctb = null; /*** * BUCKET_SET_SIZE buckets each holding 10s of processing time data, a total * of 30*10s = 5mins of processing time data is maintained */ protected static final int ONE_BUCKET_DURATION_SECONDS = 10;// seconds protected static final long ONE_BUCKET_DURATION_NANOSECONDS = ONE_BUCKET_DURATION_SECONDS * 1000000000; @Override public void bootstrap(List listeners) { if (!isInited) { ctb = new CumulativeTimeBucket(listeners); isInited = true; } } @Override public boolean isEnabled() { return isEnabled && isInited; } @Override public void setEnabled(boolean enabled) { this.isEnabled = enabled; logger.debug("Setting module to " + isEnabled); } @Override public CumulativeTimeBucket getCtb() { return ctb; } private long startTimePktNs; private long startTimeCompNs; @Override public void recordStartTimeComp(IOFMessageListener listener) { if (isEnabled()) { startTimeCompNs = System.nanoTime(); } } @Override public void recordEndTimeComp(IOFMessageListener listener) { if (isEnabled()) { long procTime = System.nanoTime() - startTimeCompNs; ctb.updateOneComponent(listener, procTime); } } @Override public void recordStartTimePktIn() { if (isEnabled()) { startTimePktNs = System.nanoTime(); } } @Override @LogMessageDoc(level="WARN", message="Time to process packet-in exceeded threshold: {}", explanation="Time to process packet-in exceeded the configured " + "performance threshold", recommendation=LogMessageDoc.CHECK_CONTROLLER) public void recordEndTimePktIn(IOFSwitch sw, OFMessage m, FloodlightContext cntx) { if (isEnabled()) { long procTimeNs = System.nanoTime() - startTimePktNs; ctb.updatePerPacketCounters(procTimeNs); if (ptWarningThresholdInNano > 0 && procTimeNs > ptWarningThresholdInNano) { logger.warn("Time to process packet-in exceeded threshold: {}", procTimeNs/1000); } } } // IFloodlightModule methods @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IPktInProcessingTimeService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IPktInProcessingTimeService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { restApi = context.getServiceImpl(IRestApiService.class); } @Override @LogMessageDoc(level="INFO", message="Packet processing time threshold for warning" + " set to {time} ms.", explanation="Performance monitoring will log a warning if " + "packet processing time exceeds the configured threshold") public void startUp(FloodlightModuleContext context) { // Add our REST API restApi.addRestletRoutable(new PerfWebRoutable()); // TODO - Alex - change this to a config option ptWarningThresholdInNano = Long.parseLong(System.getProperty( "net.floodlightcontroller.core.PTWarningThresholdInMilli", "0")) * 1000000; if (ptWarningThresholdInNano > 0) { logger.info("Packet processing time threshold for warning" + " set to {} ms.", ptWarningThresholdInNano/1000000); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/PerfMonDataResource.java0000664000175000017500000000201012041336206032101 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Return the performance monitoring data for the get rest api call * @author subrata */ public class PerfMonDataResource extends ServerResource { protected static Logger logger = LoggerFactory.getLogger(PerfMonDataResource.class); @Get("json") public CumulativeTimeBucket handleApiQuery() { IPktInProcessingTimeService pktinProcTime = (IPktInProcessingTimeService)getContext().getAttributes(). get(IPktInProcessingTimeService.class.getCanonicalName()); setStatus(Status.SUCCESS_OK, "OK"); // Allocate output object if (pktinProcTime.isEnabled()) { CumulativeTimeBucket ctb = pktinProcTime.getCtb(); ctb.computeAverages(); return ctb; } return null; } }floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/PerfWebRoutable.java0000664000175000017500000000121112041336206031263 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import net.floodlightcontroller.restserver.RestletRoutable; public class PerfWebRoutable implements RestletRoutable { @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/data/json", PerfMonDataResource.class); router.attach("/{perfmonstate}/json", PerfMonToggleResource.class); // enable, disable, or reset return router; } @Override public String basePath() { return "/wm/performance"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucket.java0000664000175000017500000000722512041336206032341 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.codehaus.jackson.map.annotate.JsonSerialize; import net.floodlightcontroller.core.IOFMessageListener; @JsonSerialize(using=CumulativeTimeBucketJSONSerializer.class) public class CumulativeTimeBucket { private long startTime_ns; // First pkt time-stamp in this bucket private Map compStats; private long totalPktCnt; private long totalProcTimeNs; // total processing time for one pkt in private long sumSquaredProcTimeNs2; private long maxTotalProcTimeNs; private long minTotalProcTimeNs; private long avgTotalProcTimeNs; private long sigmaTotalProcTimeNs; // std. deviation public long getStartTimeNs() { return startTime_ns; } public long getTotalPktCnt() { return totalPktCnt; } public long getAverageProcTimeNs() { return avgTotalProcTimeNs; } public long getMinTotalProcTimeNs() { return minTotalProcTimeNs; } public long getMaxTotalProcTimeNs() { return maxTotalProcTimeNs; } public long getTotalSigmaProcTimeNs() { return sigmaTotalProcTimeNs; } public int getNumComps() { return compStats.values().size(); } public Collection getModules() { return compStats.values(); } public CumulativeTimeBucket(List listeners) { compStats = new ConcurrentHashMap(listeners.size()); for (IOFMessageListener l : listeners) { OneComponentTime oct = new OneComponentTime(l); compStats.put(oct.hashCode(), oct); } startTime_ns = System.nanoTime(); } private void updateSquaredProcessingTime(long curTimeNs) { sumSquaredProcTimeNs2 += (Math.pow(curTimeNs, 2)); } /** * Resets all counters and counters for each component time */ public void reset() { startTime_ns = System.nanoTime(); totalPktCnt = 0; totalProcTimeNs = 0; avgTotalProcTimeNs = 0; sumSquaredProcTimeNs2 = 0; maxTotalProcTimeNs = Long.MIN_VALUE; minTotalProcTimeNs = Long.MAX_VALUE; sigmaTotalProcTimeNs = 0; for (OneComponentTime oct : compStats.values()) { oct.resetAllCounters(); } } private void computeSigma() { // Computes std. deviation from the sum of count numbers and from // the sum of the squares of count numbers double temp = totalProcTimeNs; temp = Math.pow(temp, 2) / totalPktCnt; temp = (sumSquaredProcTimeNs2 - temp) / totalPktCnt; sigmaTotalProcTimeNs = (long) Math.sqrt(temp); } public void computeAverages() { // Must be called last to, needs latest info computeSigma(); for (OneComponentTime oct : compStats.values()) { oct.computeSigma(); } } public void updatePerPacketCounters(long procTimeNs) { totalPktCnt++; totalProcTimeNs += procTimeNs; avgTotalProcTimeNs = totalProcTimeNs / totalPktCnt; updateSquaredProcessingTime(procTimeNs); if (procTimeNs > maxTotalProcTimeNs) { maxTotalProcTimeNs = procTimeNs; } if (procTimeNs < minTotalProcTimeNs) { minTotalProcTimeNs = procTimeNs; } } public void updateOneComponent(IOFMessageListener l, long procTimeNs) { compStats.get(l.hashCode()).updatePerPacketCounters(procTimeNs); } }floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java0000664000175000017500000000565212041336206033004 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.openflow.protocol.OFMessage; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; /** * An IPktInProcessingTimeService implementation that does nothing. * This is used mainly for performance testing or if you don't * want to use the IPktInProcessingTimeService features. * @author alexreimers * */ public class NullPktInProcessingTime implements IFloodlightModule, IPktInProcessingTimeService { private CumulativeTimeBucket ctb; private boolean inited = false; public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IPktInProcessingTimeService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IPktInProcessingTimeService.class, this); return m; } @Override public Collection> getModuleDependencies() { // We don't have any dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { } @Override public void startUp(FloodlightModuleContext context) { // no-op } @Override public boolean isEnabled() { return false; } @Override public void bootstrap(List listeners) { if (!inited) ctb = new CumulativeTimeBucket(listeners); } @Override public void recordStartTimeComp(IOFMessageListener listener) { } @Override public void recordEndTimeComp(IOFMessageListener listener) { } @Override public void recordStartTimePktIn() { } @Override public void recordEndTimePktIn(IOFSwitch sw, OFMessage m, FloodlightContext cntx) { } @Override public void setEnabled(boolean enabled) { } @Override public CumulativeTimeBucket getCtb() { return ctb; } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucketJSONSerializer.javafloodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/CumulativeTimeBucketJSONSerializer.ja0000664000175000017500000000333412041336206034533 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import java.io.IOException; import java.sql.Timestamp; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; public class CumulativeTimeBucketJSONSerializer extends JsonSerializer { /** * Performs the serialization of a OneComponentTime object */ @Override public void serialize(CumulativeTimeBucket ctb, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); Timestamp ts = new Timestamp(ctb.getStartTimeNs()/1000000); jGen.writeStringField("start-time", ts.toString()); jGen.writeStringField("current-time", new Timestamp(System.currentTimeMillis()).toString()); jGen.writeNumberField("total-packets", ctb.getTotalPktCnt()); jGen.writeNumberField("average", ctb.getAverageProcTimeNs()); jGen.writeNumberField("min", ctb.getMinTotalProcTimeNs()); jGen.writeNumberField("max", ctb.getMaxTotalProcTimeNs()); jGen.writeNumberField("std-dev", ctb.getTotalSigmaProcTimeNs()); jGen.writeArrayFieldStart("modules"); for (OneComponentTime oct : ctb.getModules()) { serializer.defaultSerializeValue(oct, jGen); } jGen.writeEndArray(); jGen.writeEndObject(); } /** * Tells SimpleModule that we are the serializer for OFMatch */ @Override public Class handledType() { return CumulativeTimeBucket.class; } } floodlight-0.90/src/main/java/net/floodlightcontroller/perfmon/OneComponentTime.java0000664000175000017500000000656712041336206031501 0ustar jamespagejamespagepackage net.floodlightcontroller.perfmon; import org.codehaus.jackson.annotate.JsonProperty; import net.floodlightcontroller.core.IOFMessageListener; /** * Holds OF message processing time information for one IFloodlightModule. * @author Subrata */ public class OneComponentTime { private int compId; // hascode of IOFMessageListener private String compName; private int pktCnt; // all times in nanoseconds private long totalProcTimeNs; private long sumSquaredProcTimeNs2; // squared private long maxProcTimeNs; private long minProcTimeNs; private long avgProcTimeNs; private long sigmaProcTimeNs; // std. deviation public OneComponentTime(IOFMessageListener module) { compId = module.hashCode(); compName = module.getClass().getCanonicalName(); resetAllCounters(); } public void resetAllCounters() { maxProcTimeNs = Long.MIN_VALUE; minProcTimeNs = Long.MAX_VALUE; pktCnt = 0; totalProcTimeNs = 0; sumSquaredProcTimeNs2 = 0; avgProcTimeNs = 0; sigmaProcTimeNs = 0; } @JsonProperty("module-name") public String getCompName() { return compName; } @JsonProperty("num-packets") public int getPktCnt() { return pktCnt; } @JsonProperty("total") public long getSumProcTimeNs() { return totalProcTimeNs; } @JsonProperty("max") public long getMaxProcTimeNs() { return maxProcTimeNs; } @JsonProperty("min") public long getMinProcTimeNs() { return minProcTimeNs; } @JsonProperty("average") public long getAvgProcTimeNs() { return avgProcTimeNs; } @JsonProperty("std-dev") public long getSigmaProcTimeNs() { return sigmaProcTimeNs; } @JsonProperty("average-squared") public long getSumSquaredProcTimeNs() { return sumSquaredProcTimeNs2; } // Methods used to update the counters private void increasePktCount() { pktCnt++; } private void updateTotalProcessingTime(long procTimeNs) { totalProcTimeNs += procTimeNs; } private void updateAvgProcessTime() { avgProcTimeNs = totalProcTimeNs / pktCnt; } private void updateSquaredProcessingTime(long procTimeNs) { sumSquaredProcTimeNs2 += (Math.pow(procTimeNs, 2)); } private void calculateMinProcTime(long curTimeNs) { if (curTimeNs < minProcTimeNs) minProcTimeNs = curTimeNs; } private void calculateMaxProcTime(long curTimeNs) { if (curTimeNs > maxProcTimeNs) maxProcTimeNs = curTimeNs; } public void computeSigma() { // Computes std. deviation from the sum of count numbers and from // the sum of the squares of count numbers double temp = totalProcTimeNs; temp = Math.pow(temp, 2) / pktCnt; temp = (sumSquaredProcTimeNs2 - temp) / pktCnt; sigmaProcTimeNs = (long) Math.sqrt(temp); } public void updatePerPacketCounters(long procTimeNs) { increasePktCount(); updateTotalProcessingTime(procTimeNs); calculateMinProcTime(procTimeNs); calculateMaxProcTime(procTimeNs); updateAvgProcessTime(); updateSquaredProcessingTime(procTimeNs); } @Override public int hashCode() { return compId; } }floodlight-0.90/src/main/java/net/floodlightcontroller/threadpool/0000775000175000017500000000000012041336206026070 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/threadpool/IThreadPoolService.java0000664000175000017500000000077112041336206032433 0ustar jamespagejamespagepackage net.floodlightcontroller.threadpool; import java.util.concurrent.ScheduledExecutorService; import net.floodlightcontroller.core.module.IFloodlightService; public interface IThreadPoolService extends IFloodlightService { /** * Get the master scheduled thread pool executor maintained by the * ThreadPool provider. This can be used by other modules as a centralized * way to schedule tasks. * @return */ public ScheduledExecutorService getScheduledExecutor(); } floodlight-0.90/src/main/java/net/floodlightcontroller/threadpool/ThreadPool.java0000664000175000017500000000373512041336206031004 0ustar jamespagejamespagepackage net.floodlightcontroller.threadpool; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; public class ThreadPool implements IThreadPoolService, IFloodlightModule { protected ScheduledExecutorService executor = null; // IThreadPoolService @Override public ScheduledExecutorService getScheduledExecutor() { return executor; } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IThreadPoolService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IThreadPoolService.class, this); // We are the class that implements the service return m; } @Override public Collection> getModuleDependencies() { // No dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { executor = Executors.newScheduledThreadPool(15); } @Override public void startUp(FloodlightModuleContext context) { // no-op } } floodlight-0.90/src/main/java/net/floodlightcontroller/learningswitch/0000775000175000017500000000000012041336206026750 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java0000664000175000017500000000556012041336206033512 0ustar jamespagejamespagepackage net.floodlightcontroller.learningswitch; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.types.MacVlanPair; import org.openflow.util.HexString; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LearningSwitchTable extends ServerResource { protected static Logger log = LoggerFactory.getLogger(LearningSwitchTable.class); protected Map formatTableEntry(MacVlanPair key, short port) { Map entry = new HashMap(); entry.put("mac", HexString.toHexString(key.mac)); entry.put("vlan", key.vlan); entry.put("port", port); return entry; } protected List> getOneSwitchTable(Map switchMap) { List> switchTable = new ArrayList>(); for (Entry entry : switchMap.entrySet()) { switchTable.add(formatTableEntry(entry.getKey(), entry.getValue())); } return switchTable; } @Get("json") public Map>> getSwitchTableJson() { ILearningSwitchService lsp = (ILearningSwitchService)getContext().getAttributes(). get(ILearningSwitchService.class.getCanonicalName()); Map> table = lsp.getTable(); Map>> allSwitchTableJson = new HashMap>>(); String switchId = (String) getRequestAttributes().get("switch"); if (switchId.toLowerCase().equals("all")) { for (IOFSwitch sw : table.keySet()) { allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw))); } } else { try { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); long dpid = HexString.toLong(switchId); IOFSwitch sw = floodlightProvider.getSwitches().get(dpid); allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw))); } catch (NumberFormatException e) { log.error("Could not decode switch ID = " + switchId); setStatus(Status.CLIENT_ERROR_BAD_REQUEST); } } return allSwitchTableJson; } } floodlight-0.90/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchWebRoutable.java0000664000175000017500000000107612041336206034674 0ustar jamespagejamespagepackage net.floodlightcontroller.learningswitch; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import net.floodlightcontroller.restserver.RestletRoutable; public class LearningSwitchWebRoutable implements RestletRoutable { @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/table/{switch}/json", LearningSwitchTable.class); return router; } @Override public String basePath() { return "/wm/learningswitch"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java0000664000175000017500000005455612041336206032553 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * Floodlight * A BSD licensed, Java based OpenFlow controller * * Floodlight is a Java based OpenFlow controller originally written by David Erickson at Stanford * University. It is available under the BSD license. * * For documentation, forums, issue tracking and more visit: * * http://www.openflowhub.org/display/Floodlight/Floodlight+Home **/ package net.floodlightcontroller.learningswitch; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.types.MacVlanPair; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.restserver.IRestApiService; import org.openflow.protocol.OFError; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFFlowRemoved; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.util.HexString; import org.openflow.util.LRULinkedHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LearningSwitch implements IFloodlightModule, ILearningSwitchService, IOFMessageListener { protected static Logger log = LoggerFactory.getLogger(LearningSwitch.class); // Module dependencies protected IFloodlightProviderService floodlightProvider; protected ICounterStoreService counterStore; protected IRestApiService restApi; // Stores the learned state for each switch protected Map> macVlanToSwitchPortMap; // flow-mod - for use in the cookie public static final int LEARNING_SWITCH_APP_ID = 1; // LOOK! This should probably go in some class that encapsulates // the app cookie management public static final int APP_ID_BITS = 12; public static final int APP_ID_SHIFT = (64 - APP_ID_BITS); public static final long LEARNING_SWITCH_COOKIE = (long) (LEARNING_SWITCH_APP_ID & ((1 << APP_ID_BITS) - 1)) << APP_ID_SHIFT; // more flow-mod defaults protected static final short IDLE_TIMEOUT_DEFAULT = 5; protected static final short HARD_TIMEOUT_DEFAULT = 0; protected static final short PRIORITY_DEFAULT = 100; // for managing our map sizes protected static final int MAX_MACS_PER_SWITCH = 1000; // normally, setup reverse flow as well. Disable only for using cbench for comparison with NOX etc. protected static final boolean LEARNING_SWITCH_REVERSE_FLOW = true; /** * @param floodlightProvider the floodlightProvider to set */ public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { this.floodlightProvider = floodlightProvider; } @Override public String getName() { return "learningswitch"; } /** * Adds a host to the MAC/VLAN->SwitchPort mapping * @param sw The switch to add the mapping to * @param mac The MAC address of the host to add * @param vlan The VLAN that the host is on * @param portVal The switchport that the host is on */ protected void addToPortMap(IOFSwitch sw, long mac, short vlan, short portVal) { Map swMap = macVlanToSwitchPortMap.get(sw); if (vlan == (short) 0xffff) { // OFMatch.loadFromPacket sets VLAN ID to 0xffff if the packet contains no VLAN tag; // for our purposes that is equivalent to the default VLAN ID 0 vlan = 0; } if (swMap == null) { // May be accessed by REST API so we need to make it thread safe swMap = Collections.synchronizedMap(new LRULinkedHashMap(MAX_MACS_PER_SWITCH)); macVlanToSwitchPortMap.put(sw, swMap); } swMap.put(new MacVlanPair(mac, vlan), portVal); } /** * Removes a host from the MAC/VLAN->SwitchPort mapping * @param sw The switch to remove the mapping from * @param mac The MAC address of the host to remove * @param vlan The VLAN that the host is on */ protected void removeFromPortMap(IOFSwitch sw, long mac, short vlan) { if (vlan == (short) 0xffff) { vlan = 0; } Map swMap = macVlanToSwitchPortMap.get(sw); if (swMap != null) swMap.remove(new MacVlanPair(mac, vlan)); } /** * Get the port that a MAC/VLAN pair is associated with * @param sw The switch to get the mapping from * @param mac The MAC address to get * @param vlan The VLAN number to get * @return The port the host is on */ public Short getFromPortMap(IOFSwitch sw, long mac, short vlan) { if (vlan == (short) 0xffff) { vlan = 0; } Map swMap = macVlanToSwitchPortMap.get(sw); if (swMap != null) return swMap.get(new MacVlanPair(mac, vlan)); // if none found return null; } /** * Clears the MAC/VLAN -> SwitchPort map for all switches */ public void clearLearnedTable() { macVlanToSwitchPortMap.clear(); } /** * Clears the MAC/VLAN -> SwitchPort map for a single switch * @param sw The switch to clear the mapping for */ public void clearLearnedTable(IOFSwitch sw) { Map swMap = macVlanToSwitchPortMap.get(sw); if (swMap != null) swMap.clear(); } @Override public synchronized Map> getTable() { return macVlanToSwitchPortMap; } /** * Writes a OFFlowMod to a switch. * @param sw The switch tow rite the flowmod to. * @param command The FlowMod actions (add, delete, etc). * @param bufferId The buffer ID if the switch has buffered the packet. * @param match The OFMatch structure to write. * @param outPort The switch port to output it to. */ private void writeFlowMod(IOFSwitch sw, short command, int bufferId, OFMatch match, short outPort) { // from openflow 1.0 spec - need to set these on a struct ofp_flow_mod: // struct ofp_flow_mod { // struct ofp_header header; // struct ofp_match match; /* Fields to match */ // uint64_t cookie; /* Opaque controller-issued identifier. */ // // /* Flow actions. */ // uint16_t command; /* One of OFPFC_*. */ // uint16_t idle_timeout; /* Idle time before discarding (seconds). */ // uint16_t hard_timeout; /* Max time before discarding (seconds). */ // uint16_t priority; /* Priority level of flow entry. */ // uint32_t buffer_id; /* Buffered packet to apply to (or -1). // Not meaningful for OFPFC_DELETE*. */ // uint16_t out_port; /* For OFPFC_DELETE* commands, require // matching entries to include this as an // output port. A value of OFPP_NONE // indicates no restriction. */ // uint16_t flags; /* One of OFPFF_*. */ // struct ofp_action_header actions[0]; /* The action length is inferred // from the length field in the // header. */ // }; OFFlowMod flowMod = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); flowMod.setMatch(match); flowMod.setCookie(LearningSwitch.LEARNING_SWITCH_COOKIE); flowMod.setCommand(command); flowMod.setIdleTimeout(LearningSwitch.IDLE_TIMEOUT_DEFAULT); flowMod.setHardTimeout(LearningSwitch.HARD_TIMEOUT_DEFAULT); flowMod.setPriority(LearningSwitch.PRIORITY_DEFAULT); flowMod.setBufferId(bufferId); flowMod.setOutPort((command == OFFlowMod.OFPFC_DELETE) ? outPort : OFPort.OFPP_NONE.getValue()); flowMod.setFlags((command == OFFlowMod.OFPFC_DELETE) ? 0 : (short) (1 << 0)); // OFPFF_SEND_FLOW_REM // set the ofp_action_header/out actions: // from the openflow 1.0 spec: need to set these on a struct ofp_action_output: // uint16_t type; /* OFPAT_OUTPUT. */ // uint16_t len; /* Length is 8. */ // uint16_t port; /* Output port. */ // uint16_t max_len; /* Max length to send to controller. */ // type/len are set because it is OFActionOutput, // and port, max_len are arguments to this constructor flowMod.setActions(Arrays.asList((OFAction) new OFActionOutput(outPort, (short) 0xffff))); flowMod.setLength((short) (OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH)); if (log.isTraceEnabled()) { log.trace("{} {} flow mod {}", new Object[]{ sw, (command == OFFlowMod.OFPFC_DELETE) ? "deleting" : "adding", flowMod }); } counterStore.updatePktOutFMCounterStore(sw, flowMod); // and write it out try { sw.write(flowMod, null); } catch (IOException e) { log.error("Failed to write {} to switch {}", new Object[]{ flowMod, sw }, e); } } /** * Writes an OFPacketOut message to a switch. * @param sw The switch to write the PacketOut to. * @param packetInMessage The corresponding PacketIn. * @param egressPort The switchport to output the PacketOut. */ private void writePacketOutForPacketIn(IOFSwitch sw, OFPacketIn packetInMessage, short egressPort) { // from openflow 1.0 spec - need to set these on a struct ofp_packet_out: // uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ // uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ // uint16_t actions_len; /* Size of action array in bytes. */ // struct ofp_action_header actions[0]; /* Actions. */ /* uint8_t data[0]; */ /* Packet data. The length is inferred from the length field in the header. (Only meaningful if buffer_id == -1.) */ OFPacketOut packetOutMessage = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); short packetOutLength = (short)OFPacketOut.MINIMUM_LENGTH; // starting length // Set buffer_id, in_port, actions_len packetOutMessage.setBufferId(packetInMessage.getBufferId()); packetOutMessage.setInPort(packetInMessage.getInPort()); packetOutMessage.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH); packetOutLength += OFActionOutput.MINIMUM_LENGTH; // set actions List actions = new ArrayList(1); actions.add(new OFActionOutput(egressPort, (short) 0)); packetOutMessage.setActions(actions); // set data - only if buffer_id == -1 if (packetInMessage.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { byte[] packetData = packetInMessage.getPacketData(); packetOutMessage.setPacketData(packetData); packetOutLength += (short)packetData.length; } // finally, set the total length packetOutMessage.setLength(packetOutLength); // and write it out try { counterStore.updatePktOutFMCounterStore(sw, packetOutMessage); sw.write(packetOutMessage, null); } catch (IOException e) { log.error("Failed to write {} to switch {}: {}", new Object[]{ packetOutMessage, sw, e }); } } /** * Processes a OFPacketIn message. If the switch has learned the MAC/VLAN to port mapping * for the pair it will write a FlowMod for. If the mapping has not been learned the * we will flood the packet. * @param sw * @param pi * @param cntx * @return */ private Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { // Read in packet data headers by using OFMatch OFMatch match = new OFMatch(); match.loadFromPacket(pi.getPacketData(), pi.getInPort()); Long sourceMac = Ethernet.toLong(match.getDataLayerSource()); Long destMac = Ethernet.toLong(match.getDataLayerDestination()); Short vlan = match.getDataLayerVirtualLan(); if ((destMac & 0xfffffffffff0L) == 0x0180c2000000L) { if (log.isTraceEnabled()) { log.trace("ignoring packet addressed to 802.1D/Q reserved addr: switch {} vlan {} dest MAC {}", new Object[]{ sw, vlan, HexString.toHexString(destMac) }); } return Command.STOP; } if ((sourceMac & 0x010000000000L) == 0) { // If source MAC is a unicast address, learn the port for this MAC/VLAN this.addToPortMap(sw, sourceMac, vlan, pi.getInPort()); } // Now output flow-mod and/or packet Short outPort = getFromPortMap(sw, destMac, vlan); if (outPort == null) { // If we haven't learned the port for the dest MAC/VLAN, flood it // Don't flood broadcast packets if the broadcast is disabled. // XXX For LearningSwitch this doesn't do much. The sourceMac is removed // from port map whenever a flow expires, so you would still see // a lot of floods. this.writePacketOutForPacketIn(sw, pi, OFPort.OFPP_FLOOD.getValue()); } else if (outPort == match.getInputPort()) { log.trace("ignoring packet that arrived on same port as learned destination:" + " switch {} vlan {} dest MAC {} port {}", new Object[]{ sw, vlan, HexString.toHexString(destMac), outPort }); } else { // Add flow table entry matching source MAC, dest MAC, VLAN and input port // that sends to the port we previously learned for the dest MAC/VLAN. Also // add a flow table entry with source and destination MACs reversed, and // input and output ports reversed. When either entry expires due to idle // timeout, remove the other one. This ensures that if a device moves to // a different port, a constant stream of packets headed to the device at // its former location does not keep the stale entry alive forever. // FIXME: current HP switches ignore DL_SRC and DL_DST fields, so we have to match on // NW_SRC and NW_DST as well match.setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue() & ~OFMatch.OFPFW_IN_PORT & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK); this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, pi.getBufferId(), match, outPort); if (LEARNING_SWITCH_REVERSE_FLOW) { this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, -1, match.clone() .setDataLayerSource(match.getDataLayerDestination()) .setDataLayerDestination(match.getDataLayerSource()) .setNetworkSource(match.getNetworkDestination()) .setNetworkDestination(match.getNetworkSource()) .setTransportSource(match.getTransportDestination()) .setTransportDestination(match.getTransportSource()) .setInputPort(outPort), match.getInputPort()); } } return Command.CONTINUE; } /** * Processes a flow removed message. We will delete the learned MAC/VLAN mapping from * the switch's table. * @param sw The switch that sent the flow removed message. * @param flowRemovedMessage The flow removed message. * @return Whether to continue processing this message or stop. */ private Command processFlowRemovedMessage(IOFSwitch sw, OFFlowRemoved flowRemovedMessage) { if (flowRemovedMessage.getCookie() != LearningSwitch.LEARNING_SWITCH_COOKIE) { return Command.CONTINUE; } if (log.isTraceEnabled()) { log.trace("{} flow entry removed {}", sw, flowRemovedMessage); } OFMatch match = flowRemovedMessage.getMatch(); // When a flow entry expires, it means the device with the matching source // MAC address and VLAN either stopped sending packets or moved to a different // port. If the device moved, we can't know where it went until it sends // another packet, allowing us to re-learn its port. Meanwhile we remove // it from the macVlanToPortMap to revert to flooding packets to this device. this.removeFromPortMap(sw, Ethernet.toLong(match.getDataLayerSource()), match.getDataLayerVirtualLan()); // Also, if packets keep coming from another device (e.g. from ping), the // corresponding reverse flow entry will never expire on its own and will // send the packets to the wrong port (the matching input port of the // expired flow entry), so we must delete the reverse entry explicitly. this.writeFlowMod(sw, OFFlowMod.OFPFC_DELETE, -1, match.clone() .setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue() & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK) .setDataLayerSource(match.getDataLayerDestination()) .setDataLayerDestination(match.getDataLayerSource()) .setNetworkSource(match.getNetworkDestination()) .setNetworkDestination(match.getNetworkSource()) .setTransportSource(match.getTransportDestination()) .setTransportDestination(match.getTransportSource()), match.getInputPort()); return Command.CONTINUE; } // IOFMessageListener @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx); case FLOW_REMOVED: return this.processFlowRemovedMessage(sw, (OFFlowRemoved) msg); case ERROR: log.info("received an error {} from switch {}", (OFError) msg, sw); return Command.CONTINUE; default: break; } log.error("received an unexpected message {} from switch {}", msg, sw); return Command.CONTINUE; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(ILearningSwitchService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(ILearningSwitchService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(ICounterStoreService.class); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { macVlanToSwitchPortMap = new ConcurrentHashMap>(); floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); counterStore = context.getServiceImpl(ICounterStoreService.class); restApi = context.getServiceImpl(IRestApiService.class); } @Override public void startUp(FloodlightModuleContext context) { floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this); floodlightProvider.addOFMessageListener(OFType.ERROR, this); restApi.addRestletRoutable(new LearningSwitchWebRoutable()); } } floodlight-0.90/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java0000664000175000017500000000074412041336206034173 0ustar jamespagejamespagepackage net.floodlightcontroller.learningswitch; import java.util.Map; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.types.MacVlanPair; public interface ILearningSwitchService extends IFloodlightService { /** * Returns the LearningSwitch's learned host table * @return The learned host table */ public Map> getTable(); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/0000775000175000017500000000000012041336206024657 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java0000664000175000017500000000254112041336206031154 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; /** * * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IOFMessageListener extends IListener { /** * This is the method Floodlight uses to call listeners with OpenFlow messages * @param sw the OpenFlow switch that sent this message * @param msg the message * @param cntx a Floodlight message context object you can use to pass * information between listeners * @return the command to continue or stop the execution */ public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/Main.java0000664000175000017500000000343612041336206026414 0ustar jamespagejamespagepackage net.floodlightcontroller.core; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import net.floodlightcontroller.core.internal.CmdLineSettings; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.FloodlightModuleLoader; import net.floodlightcontroller.core.module.IFloodlightModuleContext; import net.floodlightcontroller.restserver.IRestApiService; /** * Host for the Floodlight main method * @author alexreimers */ public class Main { /** * Main method to load configuration and modules * @param args * @throws FloodlightModuleException */ public static void main(String[] args) throws FloodlightModuleException { // Setup logger System.setProperty("org.restlet.engine.loggerFacadeClass", "org.restlet.ext.slf4j.Slf4jLoggerFacade"); CmdLineSettings settings = new CmdLineSettings(); CmdLineParser parser = new CmdLineParser(settings); try { parser.parseArgument(args); } catch (CmdLineException e) { parser.printUsage(System.out); System.exit(1); } // Load modules FloodlightModuleLoader fml = new FloodlightModuleLoader(); IFloodlightModuleContext moduleContext = fml.loadModulesFromConfig(settings.getModuleFile()); // Run REST server IRestApiService restApi = moduleContext.getServiceImpl(IRestApiService.class); restApi.run(); // Run the main floodlight module IFloodlightProviderService controller = moduleContext.getServiceImpl(IFloodlightProviderService.class); // This call blocks, it has to be the last line in the main controller.run(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IListener.java0000664000175000017500000000355512041336206027430 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; public interface IListener { public enum Command { CONTINUE, STOP } /** * The name assigned to this listener * @return */ public String getName(); /** * Check if the module called name is a callback ordering prerequisite * for this module. In other words, if this function returns true for * the given name, then this message listener will be called after that * message listener. * @param type the message type to which this applies * @param name the name of the module * @return whether name is a prerequisite. */ public boolean isCallbackOrderingPrereq(T type, String name); /** * Check if the module called name is a callback ordering post-requisite * for this module. In other words, if this function returns true for * the given name, then this message listener will be called before that * message listener. * @param type the message type to which this applies * @param name the name of the module * @return whether name is a post-requisite. */ public boolean isCallbackOrderingPostreq(T type, String name); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IOFSwitchFilter.java0000664000175000017500000000257412041336206030477 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; /** * Used in conjunction with {@link IOFMessageListener} to allow a listener to * filter an incoming message based on the {@link IOFSwitch} it originated from. * Implementations wanting to use this interface should implement both * IOFMessageListener and IOFSwitchFilter. * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IOFSwitchFilter { /** * The result of this method call determines whether the * IOFMessageListener's receive method is called or not. * * @param sw switch to filter on * @return true to receive the message, false to ignore */ public boolean isInterested(IOFSwitch sw); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IHAListener.java0000664000175000017500000000211212041336206027625 0ustar jamespagejamespagepackage net.floodlightcontroller.core; import java.util.Map; import net.floodlightcontroller.core.IFloodlightProviderService.Role; public interface IHAListener { /** * Gets called when the controller changes role (i.e. Master -> Slave). * Note that oldRole CAN be null. * @param oldRole The controller's old role * @param newRole The controller's new role */ public void roleChanged(Role oldRole, Role newRole); /** * Gets called when the IP addresses of the controller nodes in the * controller cluster change. All parameters map controller ID to * the controller's IP. * * @param curControllerNodeIPs The current mapping of controller IDs to IP * @param addedControllerNodeIPs These IPs were added since the last update * @param removedControllerNodeIPs These IPs were removed since the last update */ public void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs ); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IOFMessageFilterManagerService.java0000664000175000017500000000031512041336206033425 0ustar jamespagejamespagepackage net.floodlightcontroller.core; import net.floodlightcontroller.core.module.IFloodlightService; public interface IOFMessageFilterManagerService extends IFloodlightService { // empty for now } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/0000775000175000017500000000000012041336206026473 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java0000664000175000017500000000343412041336206032453 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import org.openflow.protocol.OFMessage; /** * Encode an openflow message for output into a ChannelBuffer, for use in a * netty pipeline * @author readams */ public class OFMessageEncoder extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { if (!( msg instanceof List)) return msg; @SuppressWarnings("unchecked") List msglist = (List)msg; int size = 0; for (OFMessage ofm : msglist) { size += ofm.getLengthU(); } ChannelBuffer buf = ChannelBuffers.buffer(size);; for (OFMessage ofm : msglist) { ofm.writeTo(buf); } return buf; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java0000664000175000017500000000540512041336206034151 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.concurrent.ThreadPoolExecutor; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.execution.ExecutionHandler; import org.jboss.netty.handler.timeout.IdleStateHandler; import org.jboss.netty.handler.timeout.ReadTimeoutHandler; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timer; /** * Creates a ChannelPipeline for a server-side openflow channel * @author readams */ public class OpenflowPipelineFactory implements ChannelPipelineFactory { protected Controller controller; protected ThreadPoolExecutor pipelineExecutor; protected Timer timer; protected IdleStateHandler idleHandler; protected ReadTimeoutHandler readTimeoutHandler; public OpenflowPipelineFactory(Controller controller, ThreadPoolExecutor pipelineExecutor) { super(); this.controller = controller; this.pipelineExecutor = pipelineExecutor; this.timer = new HashedWheelTimer(); this.idleHandler = new IdleStateHandler(timer, 20, 25, 0); this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30); } @Override public ChannelPipeline getPipeline() throws Exception { OFChannelState state = new OFChannelState(); ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("ofmessagedecoder", new OFMessageDecoder()); pipeline.addLast("ofmessageencoder", new OFMessageEncoder()); pipeline.addLast("idle", idleHandler); pipeline.addLast("timeout", readTimeoutHandler); pipeline.addLast("handshaketimeout", new HandshakeTimeoutHandler(state, timer, 15)); if (pipelineExecutor != null) pipeline.addLast("pipelineExecutor", new ExecutionHandler(pipelineExecutor)); pipeline.addLast("handler", controller.getChannelHandler(state)); return pipeline; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java0000664000175000017500000000622112041336206034072 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; /** * Trigger a timeout if a switch fails to complete handshake soon enough */ public class HandshakeTimeoutHandler extends SimpleChannelUpstreamHandler implements ExternalResourceReleasable { static final HandshakeTimeoutException EXCEPTION = new HandshakeTimeoutException(); final OFChannelState state; final Timer timer; final long timeoutNanos; volatile Timeout timeout; public HandshakeTimeoutHandler(OFChannelState state, Timer timer, long timeoutSeconds) { super(); this.state = state; this.timer = timer; this.timeoutNanos = TimeUnit.SECONDS.toNanos(timeoutSeconds); } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (timeoutNanos > 0) { timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx), timeoutNanos, TimeUnit.NANOSECONDS); } ctx.sendUpstream(e); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (timeout != null) { timeout.cancel(); timeout = null; } } @Override public void releaseExternalResources() { timer.stop(); } private final class HandshakeTimeoutTask implements TimerTask { private final ChannelHandlerContext ctx; HandshakeTimeoutTask(ChannelHandlerContext ctx) { this.ctx = ctx; } @Override public void run(Timeout timeout) throws Exception { if (timeout.isCancelled()) { return; } if (!ctx.getChannel().isOpen()) { return; } if (!state.hsState.equals(HandshakeState.READY)) Channels.fireExceptionCaught(ctx, EXCEPTION); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java0000664000175000017500000000365612041336206032146 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; /** * Wrapper class to hold state for the OpenFlow switch connection * @author readams */ class OFChannelState { /** * State for handling the switch handshake */ protected enum HandshakeState { /** * Beginning state */ START, /** * Received HELLO from switch */ HELLO, /** * We've received the features reply * Waiting for Config and Description reply */ FEATURES_REPLY, /** * Switch is ready for processing messages */ READY } protected volatile HandshakeState hsState = HandshakeState.START; protected boolean hasGetConfigReply = false; protected boolean hasDescription = false; // The firstRoleReplyRecevied flag indicates if we have received the // first role reply message on this connection (in response to the // role request sent after the handshake). If role support is disabled // on the controller we also set this flag to true. // The flag is used to decide if the flow table should be wiped // @see Controller.handleRoleReplyMessage() protected boolean firstRoleReplyReceived = false; }floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java0000664000175000017500000001240712041336206032346 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.threadpool.IThreadPoolService; /** * A Future object used to retrieve asynchronous OFMessage replies. Unregisters * and cancels itself by default after 60 seconds. This class is meant to be * sub-classed and proper behavior added to the handleReply method, and * termination of the Future to be handled in the isFinished method. * * @author David Erickson (daviderickson@cs.stanford.edu) */ public abstract class OFMessageFuture implements Future { protected IThreadPoolService threadPool; protected volatile boolean canceled; protected CountDownLatch latch; protected OFType responseType; protected volatile V result; protected IOFSwitch sw; protected Runnable timeoutTimer; protected int transactionId; protected static final long DEFAULT_TIMEOUT = 60; protected static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS; public OFMessageFuture(IThreadPoolService tp, IOFSwitch sw, OFType responseType, int transactionId) { this(tp, sw, responseType, transactionId, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT); } public OFMessageFuture(IThreadPoolService tp, IOFSwitch sw, OFType responseType, int transactionId, long timeout, TimeUnit unit) { this.threadPool = tp; this.canceled = false; this.latch = new CountDownLatch(1); this.responseType = responseType; this.sw = sw; this.transactionId = transactionId; final OFMessageFuture future = this; timeoutTimer = new Runnable() { @Override public void run() { if (timeoutTimer == this) future.cancel(true); } }; threadPool.getScheduledExecutor().schedule(timeoutTimer, timeout, unit); } protected void unRegister() { this.timeoutTimer = null; } public void deliverFuture(IOFSwitch sw, OFMessage msg) { if (transactionId == msg.getXid()) { handleReply(sw, msg); if (isFinished()) { unRegister(); this.latch.countDown(); } } } /** * Used to handle the specific expected message this Future was reigstered * for, the specified msg parameter is guaranteed to match the type and * transaction id specified. * @param sw * @param msg * @return */ protected abstract void handleReply(IOFSwitch sw, OFMessage msg); /** * Called directly after handleReply, subclasses implement this method to * indicate when the future can deregister itself from receiving future * messages, and when it is safe to return the results to any waiting * threads. * @return when this Future has completed its work */ protected abstract boolean isFinished(); /* (non-Javadoc) * @see java.util.concurrent.Future#cancel(boolean) */ @Override public boolean cancel(boolean mayInterruptIfRunning) { if (isDone()) { return false; } else { unRegister(); canceled = true; this.latch.countDown(); return !isDone(); } } /* (non-Javadoc) * @see java.util.concurrent.Future#isCancelled() */ @Override public boolean isCancelled() { return canceled; } /* (non-Javadoc) * @see java.util.concurrent.Future#isDone() */ @Override public boolean isDone() { return this.latch.getCount() == 0; } /* (non-Javadoc) * @see java.util.concurrent.Future#get() */ @Override public V get() throws InterruptedException, ExecutionException { this.latch.await(); return result; } /* (non-Javadoc) * @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit) */ @Override public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { this.latch.await(timeout, unit); return result; } public int getTransactionId() { return transactionId; } public void setTransactionId(int transactionId) { this.transactionId = transactionId; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/Controller.java0000664000175000017500000030520712041336206031470 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.nio.channels.ClosedChannelException; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.Stack; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState; import net.floodlightcontroller.core.util.ListenerDispatcher; import net.floodlightcontroller.core.web.CoreWebRoutable; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IStorageSourceListener; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.OperatorPredicate; import net.floodlightcontroller.storage.StorageException; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelUpstreamHandler; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler; import org.jboss.netty.handler.timeout.IdleStateEvent; import org.jboss.netty.handler.timeout.ReadTimeoutException; import org.openflow.protocol.OFEchoReply; import org.openflow.protocol.OFError; import org.openflow.protocol.OFError.OFBadActionCode; import org.openflow.protocol.OFError.OFBadRequestCode; import org.openflow.protocol.OFError.OFErrorType; import org.openflow.protocol.OFError.OFFlowModFailedCode; import org.openflow.protocol.OFError.OFHelloFailedCode; import org.openflow.protocol.OFError.OFPortModFailedCode; import org.openflow.protocol.OFError.OFQueueOpFailedCode; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFGetConfigReply; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFPortStatus; import org.openflow.protocol.OFPortStatus.OFPortReason; import org.openflow.protocol.OFSetConfig; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.OFSwitchConfig; import org.openflow.protocol.OFType; import org.openflow.protocol.OFVendor; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.MessageParseException; import org.openflow.protocol.statistics.OFDescriptionStatistics; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.protocol.vendor.OFBasicVendorDataType; import org.openflow.protocol.vendor.OFBasicVendorId; import org.openflow.protocol.vendor.OFVendorId; import org.openflow.util.HexString; import org.openflow.util.U16; import org.openflow.util.U32; import org.openflow.vendor.nicira.OFNiciraVendorData; import org.openflow.vendor.nicira.OFRoleReplyVendorData; import org.openflow.vendor.nicira.OFRoleRequestVendorData; import org.openflow.vendor.nicira.OFRoleVendorData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The main controller class. Handles all setup and network listeners */ public class Controller implements IFloodlightProviderService, IStorageSourceListener { protected static Logger log = LoggerFactory.getLogger(Controller.class); private static final String ERROR_DATABASE = "The controller could not communicate with the system database."; protected BasicFactory factory; protected ConcurrentMap> messageListeners; // The activeSwitches map contains only those switches that are actively // being controlled by us -- it doesn't contain switches that are // in the slave role protected ConcurrentHashMap activeSwitches; // connectedSwitches contains all connected switches, including ones where // we're a slave controller. We need to keep track of them so that we can // send role request messages to switches when our role changes to master // We add a switch to this set after it successfully completes the // handshake. Access to this Set needs to be synchronized with roleChanger protected HashSet connectedSwitches; // The controllerNodeIPsCache maps Controller IDs to their IP address. // It's only used by handleControllerNodeIPsChanged protected HashMap controllerNodeIPsCache; protected Set switchListeners; protected Set haListeners; protected Map> providerMap; protected BlockingQueue updates; // Module dependencies protected IRestApiService restApi; protected ICounterStoreService counterStore = null; protected IStorageSourceService storageSource; protected IPktInProcessingTimeService pktinProcTime; protected IThreadPoolService threadPool; // Configuration options protected int openFlowPort = 6633; protected int workerThreads = 0; // The id for this controller node. Should be unique for each controller // node in a controller cluster. protected String controllerId = "localhost"; // The current role of the controller. // If the controller isn't configured to support roles, then this is null. protected Role role; // A helper that handles sending and timeout handling for role requests protected RoleChanger roleChanger; // Start time of the controller protected long systemStartTime; // Flag to always flush flow table on switch reconnect (HA or otherwise) protected boolean alwaysClearFlowsOnSwAdd = false; // Storage table names protected static final String CONTROLLER_TABLE_NAME = "controller_controller"; protected static final String CONTROLLER_ID = "id"; protected static final String SWITCH_TABLE_NAME = "controller_switch"; protected static final String SWITCH_DATAPATH_ID = "dpid"; protected static final String SWITCH_SOCKET_ADDRESS = "socket_address"; protected static final String SWITCH_IP = "ip"; protected static final String SWITCH_CONTROLLER_ID = "controller_id"; protected static final String SWITCH_ACTIVE = "active"; protected static final String SWITCH_CONNECTED_SINCE = "connected_since"; protected static final String SWITCH_CAPABILITIES = "capabilities"; protected static final String SWITCH_BUFFERS = "buffers"; protected static final String SWITCH_TABLES = "tables"; protected static final String SWITCH_ACTIONS = "actions"; protected static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig"; protected static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch"; protected static final String PORT_TABLE_NAME = "controller_port"; protected static final String PORT_ID = "id"; protected static final String PORT_SWITCH = "switch_id"; protected static final String PORT_NUMBER = "number"; protected static final String PORT_HARDWARE_ADDRESS = "hardware_address"; protected static final String PORT_NAME = "name"; protected static final String PORT_CONFIG = "config"; protected static final String PORT_STATE = "state"; protected static final String PORT_CURRENT_FEATURES = "current_features"; protected static final String PORT_ADVERTISED_FEATURES = "advertised_features"; protected static final String PORT_SUPPORTED_FEATURES = "supported_features"; protected static final String PORT_PEER_FEATURES = "peer_features"; protected static final String CONTROLLER_INTERFACE_TABLE_NAME = "controller_controllerinterface"; protected static final String CONTROLLER_INTERFACE_ID = "id"; protected static final String CONTROLLER_INTERFACE_CONTROLLER_ID = "controller_id"; protected static final String CONTROLLER_INTERFACE_TYPE = "type"; protected static final String CONTROLLER_INTERFACE_NUMBER = "number"; protected static final String CONTROLLER_INTERFACE_DISCOVERED_IP = "discovered_ip"; // Perf. related configuration protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024; protected static final int BATCH_MAX_SIZE = 100; protected static final boolean ALWAYS_DECODE_ETH = true; /** * Updates handled by the main loop */ protected interface IUpdate { /** * Calls the appropriate listeners */ public void dispatch(); } public enum SwitchUpdateType { ADDED, REMOVED, PORTCHANGED } /** * Update message indicating a switch was added or removed */ protected class SwitchUpdate implements IUpdate { public IOFSwitch sw; public SwitchUpdateType switchUpdateType; public SwitchUpdate(IOFSwitch sw, SwitchUpdateType switchUpdateType) { this.sw = sw; this.switchUpdateType = switchUpdateType; } public void dispatch() { if (log.isTraceEnabled()) { log.trace("Dispatching switch update {} {}", sw, switchUpdateType); } if (switchListeners != null) { for (IOFSwitchListener listener : switchListeners) { switch(switchUpdateType) { case ADDED: listener.addedSwitch(sw); break; case REMOVED: listener.removedSwitch(sw); break; case PORTCHANGED: listener.switchPortChanged(sw.getId()); break; } } } } } /** * Update message indicating controller's role has changed */ protected class HARoleUpdate implements IUpdate { public Role oldRole; public Role newRole; public HARoleUpdate(Role newRole, Role oldRole) { this.oldRole = oldRole; this.newRole = newRole; } public void dispatch() { // Make sure that old and new roles are different. if (oldRole == newRole) { if (log.isTraceEnabled()) { log.trace("HA role update ignored as the old and " + "new roles are the same. newRole = {}" + "oldRole = {}", newRole, oldRole); } return; } if (log.isTraceEnabled()) { log.trace("Dispatching HA Role update newRole = {}, oldRole = {}", newRole, oldRole); } if (haListeners != null) { for (IHAListener listener : haListeners) { listener.roleChanged(oldRole, newRole); } } } } /** * Update message indicating * IPs of controllers in controller cluster have changed. */ protected class HAControllerNodeIPUpdate implements IUpdate { public Map curControllerNodeIPs; public Map addedControllerNodeIPs; public Map removedControllerNodeIPs; public HAControllerNodeIPUpdate( HashMap curControllerNodeIPs, HashMap addedControllerNodeIPs, HashMap removedControllerNodeIPs) { this.curControllerNodeIPs = curControllerNodeIPs; this.addedControllerNodeIPs = addedControllerNodeIPs; this.removedControllerNodeIPs = removedControllerNodeIPs; } public void dispatch() { if (log.isTraceEnabled()) { log.trace("Dispatching HA Controller Node IP update " + "curIPs = {}, addedIPs = {}, removedIPs = {}", new Object[] { curControllerNodeIPs, addedControllerNodeIPs, removedControllerNodeIPs } ); } if (haListeners != null) { for (IHAListener listener: haListeners) { listener.controllerNodeIPsChanged(curControllerNodeIPs, addedControllerNodeIPs, removedControllerNodeIPs); } } } } // *************** // Getters/Setters // *************** public void setStorageSourceService(IStorageSourceService storageSource) { this.storageSource = storageSource; } public void setCounterStore(ICounterStoreService counterStore) { this.counterStore = counterStore; } public void setPktInProcessingService(IPktInProcessingTimeService pits) { this.pktinProcTime = pits; } public void setRestApiService(IRestApiService restApi) { this.restApi = restApi; } public void setThreadPoolService(IThreadPoolService tp) { this.threadPool = tp; } @Override public Role getRole() { synchronized(roleChanger) { return role; } } @Override public void setRole(Role role) { if (role == null) throw new NullPointerException("Role can not be null."); if (role == Role.MASTER && this.role == Role.SLAVE) { // Reset db state to Inactive for all switches. updateAllInactiveSwitchInfo(); } // Need to synchronize to ensure a reliable ordering on role request // messages send and to ensure the list of connected switches is stable // RoleChanger will handle the actual sending of the message and // timeout handling // @see RoleChanger synchronized(roleChanger) { if (role.equals(this.role)) { log.debug("Ignoring role change: role is already {}", role); return; } Role oldRole = this.role; this.role = role; log.debug("Submitting role change request to role {}", role); roleChanger.submitRequest(connectedSwitches, role); // Enqueue an update for our listeners. try { this.updates.put(new HARoleUpdate(role, oldRole)); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } } // ********************** // ChannelUpstreamHandler // ********************** /** * Return a new channel handler for processing a switch connections * @param state The channel state object for the connection * @return the new channel handler */ protected ChannelUpstreamHandler getChannelHandler(OFChannelState state) { return new OFChannelHandler(state); } /** * Channel handler deals with the switch connection and dispatches * switch messages to the appropriate locations. * @author readams */ protected class OFChannelHandler extends IdleStateAwareChannelUpstreamHandler { protected OFSwitchImpl sw; protected OFChannelState state; public OFChannelHandler(OFChannelState state) { this.state = state; } @Override @LogMessageDoc(message="New switch connection from {ip address}", explanation="A new switch has connected from the " + "specified IP address") public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { log.info("New switch connection from {}", e.getChannel().getRemoteAddress()); sw = new OFSwitchImpl(); sw.setChannel(e.getChannel()); sw.setFloodlightProvider(Controller.this); sw.setThreadPoolService(threadPool); List msglist = new ArrayList(1); msglist.add(factory.getMessage(OFType.HELLO)); e.getChannel().write(msglist); } @Override @LogMessageDoc(message="Disconnected switch {switch information}", explanation="The specified switch has disconnected.") public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (sw != null && state.hsState == HandshakeState.READY) { if (activeSwitches.containsKey(sw.getId())) { // It's safe to call removeSwitch even though the map might // not contain this particular switch but another with the // same DPID removeSwitch(sw); } synchronized(roleChanger) { connectedSwitches.remove(sw); } sw.setConnected(false); } log.info("Disconnected switch {}", sw); } @Override @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Disconnecting switch {switch} due to read timeout", explanation="The connected switch has failed to send any " + "messages or respond to echo requests", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Disconnecting switch {switch}: failed to " + "complete handshake", explanation="The switch did not respond correctly " + "to handshake messages", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Disconnecting switch {switch} due to IO Error: {}", explanation="There was an error communicating with the switch", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Disconnecting switch {switch} due to switch " + "state error: {error}", explanation="The switch sent an unexpected message", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Disconnecting switch {switch} due to " + "message parse failure", explanation="Could not parse a message from the switch", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Terminating controller due to storage exception", explanation=ERROR_DATABASE, recommendation=LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Could not process message: queue full", explanation="OpenFlow messages are arriving faster than " + " the controller can process them.", recommendation=LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Error while processing message " + "from switch {switch} {cause}", explanation="An error occurred processing the switch message", recommendation=LogMessageDoc.GENERIC_ACTION) }) public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (e.getCause() instanceof ReadTimeoutException) { // switch timeout log.error("Disconnecting switch {} due to read timeout", sw); ctx.getChannel().close(); } else if (e.getCause() instanceof HandshakeTimeoutException) { log.error("Disconnecting switch {}: failed to complete handshake", sw); ctx.getChannel().close(); } else if (e.getCause() instanceof ClosedChannelException) { //log.warn("Channel for sw {} already closed", sw); } else if (e.getCause() instanceof IOException) { log.error("Disconnecting switch {} due to IO Error: {}", sw, e.getCause().getMessage()); ctx.getChannel().close(); } else if (e.getCause() instanceof SwitchStateException) { log.error("Disconnecting switch {} due to switch state error: {}", sw, e.getCause().getMessage()); ctx.getChannel().close(); } else if (e.getCause() instanceof MessageParseException) { log.error("Disconnecting switch " + sw + " due to message parse failure", e.getCause()); ctx.getChannel().close(); } else if (e.getCause() instanceof StorageException) { log.error("Terminating controller due to storage exception", e.getCause()); terminate(); } else if (e.getCause() instanceof RejectedExecutionException) { log.warn("Could not process message: queue full"); } else { log.error("Error while processing message from switch " + sw, e.getCause()); ctx.getChannel().close(); } } @Override public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception { List msglist = new ArrayList(1); msglist.add(factory.getMessage(OFType.ECHO_REQUEST)); e.getChannel().write(msglist); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof List) { @SuppressWarnings("unchecked") List msglist = (List)e.getMessage(); for (OFMessage ofm : msglist) { try { processOFMessage(ofm); } catch (Exception ex) { // We are the last handler in the stream, so run the // exception through the channel again by passing in // ctx.getChannel(). Channels.fireExceptionCaught(ctx.getChannel(), ex); } } // Flush all flow-mods/packet-out generated from this "train" OFSwitchImpl.flush_all(); } } /** * Process the request for the switch description */ @LogMessageDoc(level="ERROR", message="Exception in reading description " + " during handshake {exception}", explanation="Could not process the switch description string", recommendation=LogMessageDoc.CHECK_SWITCH) void processSwitchDescReply() { try { // Read description, if it has been updated @SuppressWarnings("unchecked") Future> desc_future = (Future>)sw. getAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE); List values = desc_future.get(0, TimeUnit.MILLISECONDS); if (values != null) { OFDescriptionStatistics description = new OFDescriptionStatistics(); ChannelBuffer data = ChannelBuffers.buffer(description.getLength()); for (OFStatistics f : values) { f.writeTo(data); description.readFrom(data); break; // SHOULD be a list of length 1 } sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA, description); sw.setSwitchProperties(description); data = null; // At this time, also set other switch properties from storage boolean is_core_switch = false; IResultSet resultSet = null; try { String swid = sw.getStringId(); resultSet = storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid); for (Iterator it = resultSet.iterator(); it.hasNext();) { // In case of multiple rows, use the status // in last row? Map row = it.next().getRow(); if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) { if (log.isDebugEnabled()) { log.debug("Reading SWITCH_IS_CORE_SWITCH " + "config for switch={}, is-core={}", sw, row.get(SWITCH_CONFIG_CORE_SWITCH)); } String ics = (String)row.get(SWITCH_CONFIG_CORE_SWITCH); is_core_switch = ics.equals("true"); } } } finally { if (resultSet != null) resultSet.close(); } if (is_core_switch) { sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true)); } } sw.removeAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE); state.hasDescription = true; checkSwitchReady(); } catch (InterruptedException ex) { // Ignore } catch (TimeoutException ex) { // Ignore } catch (Exception ex) { log.error("Exception in reading description " + " during handshake", ex); } } /** * Send initial switch setup information that we need before adding * the switch * @throws IOException */ void sendHelloConfiguration() throws IOException { // Send initial Features Request sw.write(factory.getMessage(OFType.FEATURES_REQUEST), null); } /** * Send the configuration requests we can only do after we have * the features reply * @throws IOException */ void sendFeatureReplyConfiguration() throws IOException { // Ensure we receive the full packet via PacketIn OFSetConfig config = (OFSetConfig) factory .getMessage(OFType.SET_CONFIG); config.setMissSendLength((short) 0xffff) .setLengthU(OFSwitchConfig.MINIMUM_LENGTH); sw.write(config, null); sw.write(factory.getMessage(OFType.GET_CONFIG_REQUEST), null); // Get Description to set switch-specific flags OFStatisticsRequest req = new OFStatisticsRequest(); req.setStatisticType(OFStatisticsType.DESC); req.setLengthU(req.getLengthU()); Future> dfuture = sw.getStatistics(req); sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE, dfuture); } protected void checkSwitchReady() { if (state.hsState == HandshakeState.FEATURES_REPLY && state.hasDescription && state.hasGetConfigReply) { state.hsState = HandshakeState.READY; synchronized(roleChanger) { // We need to keep track of all of the switches that are connected // to the controller, in any role, so that we can later send the // role request messages when the controller role changes. // We need to be synchronized while doing this: we must not // send a another role request to the connectedSwitches until // we were able to add this new switch to connectedSwitches // *and* send the current role to the new switch. connectedSwitches.add(sw); if (role != null) { // Send a role request if role support is enabled for the controller // This is a probe that we'll use to determine if the switch // actually supports the role request message. If it does we'll // get back a role reply message. If it doesn't we'll get back an // OFError message. // If role is MASTER we will promote switch to active // list when we receive the switch's role reply messages log.debug("This controller's role is {}, " + "sending initial role request msg to {}", role, sw); Collection swList = new ArrayList(1); swList.add(sw); roleChanger.submitRequest(swList, role); } else { // Role supported not enabled on controller (for now) // automatically promote switch to active state. log.debug("This controller's role is null, " + "not sending role request msg to {}", role, sw); // Need to clear FlowMods before we add the switch // and dispatch updates otherwise we have a race condition. sw.clearAllFlowMods(); addSwitch(sw); state.firstRoleReplyReceived = true; } } } } /* Handle a role reply message we received from the switch. Since * netty serializes message dispatch we don't need to synchronize * against other receive operations from the same switch, so no need * to synchronize addSwitch(), removeSwitch() operations from the same * connection. * FIXME: However, when a switch with the same DPID connects we do * need some synchronization. However, handling switches with same * DPID needs to be revisited anyways (get rid of r/w-lock and synchronous * removedSwitch notification):1 * */ @LogMessageDoc(level="ERROR", message="Invalid role value in role reply message", explanation="Was unable to set the HA role (master or slave) " + "for the controller.", recommendation=LogMessageDoc.CHECK_CONTROLLER) protected void handleRoleReplyMessage(OFVendor vendorMessage, OFRoleReplyVendorData roleReplyVendorData) { // Map from the role code in the message to our role enum int nxRole = roleReplyVendorData.getRole(); Role role = null; switch (nxRole) { case OFRoleVendorData.NX_ROLE_OTHER: role = Role.EQUAL; break; case OFRoleVendorData.NX_ROLE_MASTER: role = Role.MASTER; break; case OFRoleVendorData.NX_ROLE_SLAVE: role = Role.SLAVE; break; default: log.error("Invalid role value in role reply message"); sw.getChannel().close(); return; } log.debug("Handling role reply for role {} from {}. " + "Controller's role is {} ", new Object[] { role, sw, Controller.this.role} ); sw.deliverRoleReply(vendorMessage.getXid(), role); boolean isActive = activeSwitches.containsKey(sw.getId()); if (!isActive && sw.isActive()) { // Transition from SLAVE to MASTER. if (!state.firstRoleReplyReceived || getAlwaysClearFlowsOnSwAdd()) { // This is the first role-reply message we receive from // this switch or roles were disabled when the switch // connected: // Delete all pre-existing flows for new connections to // the master // // FIXME: Need to think more about what the test should // be for when we flush the flow-table? For example, // if all the controllers are temporarily in the backup // role (e.g. right after a failure of the master // controller) at the point the switch connects, then // all of the controllers will initially connect as // backup controllers and not flush the flow-table. // Then when one of them is promoted to master following // the master controller election the flow-table // will still not be flushed because that's treated as // a failover event where we don't want to flush the // flow-table. The end result would be that the flow // table for a newly connected switch is never // flushed. Not sure how to handle that case though... sw.clearAllFlowMods(); log.debug("First role reply from master switch {}, " + "clear FlowTable to active switch list", HexString.toHexString(sw.getId())); } // Some switches don't seem to update us with port // status messages while in slave role. readSwitchPortStateFromStorage(sw); // Only add the switch to the active switch list if // we're not in the slave role. Note that if the role // attribute is null, then that means that the switch // doesn't support the role request messages, so in that // case we're effectively in the EQUAL role and the // switch should be included in the active switch list. addSwitch(sw); log.debug("Added master switch {} to active switch list", HexString.toHexString(sw.getId())); } else if (isActive && !sw.isActive()) { // Transition from MASTER to SLAVE: remove switch // from active switch list. log.debug("Removed slave switch {} from active switch" + " list", HexString.toHexString(sw.getId())); removeSwitch(sw); } // Indicate that we have received a role reply message. state.firstRoleReplyReceived = true; } protected boolean handleVendorMessage(OFVendor vendorMessage) { boolean shouldHandleMessage = false; int vendor = vendorMessage.getVendor(); switch (vendor) { case OFNiciraVendorData.NX_VENDOR_ID: OFNiciraVendorData niciraVendorData = (OFNiciraVendorData)vendorMessage.getVendorData(); int dataType = niciraVendorData.getDataType(); switch (dataType) { case OFRoleReplyVendorData.NXT_ROLE_REPLY: OFRoleReplyVendorData roleReplyVendorData = (OFRoleReplyVendorData) niciraVendorData; handleRoleReplyMessage(vendorMessage, roleReplyVendorData); break; default: log.warn("Unhandled Nicira VENDOR message; " + "data type = {}", dataType); break; } break; default: log.warn("Unhandled VENDOR message; vendor id = {}", vendor); break; } return shouldHandleMessage; } /** * Dispatch an Openflow message from a switch to the appropriate * handler. * @param m The message to process * @throws IOException * @throws SwitchStateException */ @LogMessageDocs({ @LogMessageDoc(level="WARN", message="Config Reply from {switch} has " + "miss length set to {length}", explanation="The controller requires that the switch " + "use a miss length of 0xffff for correct " + "function", recommendation="Use a different switch to ensure " + "correct function"), @LogMessageDoc(level="WARN", message="Received ERROR from sw {switch} that " +"indicates roles are not supported " +"but we have received a valid " +"role reply earlier", explanation="The switch sent a confusing message to the" + "controller") }) protected void processOFMessage(OFMessage m) throws IOException, SwitchStateException { boolean shouldHandleMessage = false; switch (m.getType()) { case HELLO: if (log.isTraceEnabled()) log.trace("HELLO from {}", sw); if (state.hsState.equals(HandshakeState.START)) { state.hsState = HandshakeState.HELLO; sendHelloConfiguration(); } else { throw new SwitchStateException("Unexpected HELLO from " + sw); } break; case ECHO_REQUEST: OFEchoReply reply = (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY); reply.setXid(m.getXid()); sw.write(reply, null); break; case ECHO_REPLY: break; case FEATURES_REPLY: if (log.isTraceEnabled()) log.trace("Features Reply from {}", sw); sw.setFeaturesReply((OFFeaturesReply) m); if (state.hsState.equals(HandshakeState.HELLO)) { sendFeatureReplyConfiguration(); state.hsState = HandshakeState.FEATURES_REPLY; // uncomment to enable "dumb" switches like cbench // state.hsState = HandshakeState.READY; // addSwitch(sw); } else { // return results to rest api caller sw.deliverOFFeaturesReply(m); // update database */ updateActiveSwitchInfo(sw); } break; case GET_CONFIG_REPLY: if (log.isTraceEnabled()) log.trace("Get config reply from {}", sw); if (!state.hsState.equals(HandshakeState.FEATURES_REPLY)) { String em = "Unexpected GET_CONFIG_REPLY from " + sw; throw new SwitchStateException(em); } OFGetConfigReply cr = (OFGetConfigReply) m; if (cr.getMissSendLength() == (short)0xffff) { log.trace("Config Reply from {} confirms " + "miss length set to 0xffff", sw); } else { log.warn("Config Reply from {} has " + "miss length set to {}", sw, cr.getMissSendLength() & 0xffff); } state.hasGetConfigReply = true; checkSwitchReady(); break; case VENDOR: shouldHandleMessage = handleVendorMessage((OFVendor)m); break; case ERROR: // TODO: we need better error handling. Especially for // request/reply style message (stats, roles) we should have // a unified way to lookup the xid in the error message. // This will probable involve rewriting the way we handle // request/reply style messages. OFError error = (OFError) m; boolean shouldLogError = true; // TODO: should we check that firstRoleReplyReceived is false, // i.e., check only whether the first request fails? if (sw.checkFirstPendingRoleRequestXid(error.getXid())) { boolean isBadVendorError = (error.getErrorType() == OFError.OFErrorType. OFPET_BAD_REQUEST.getValue()); // We expect to receive a bad vendor error when // we're connected to a switch that doesn't support // the Nicira vendor extensions (i.e. not OVS or // derived from OVS). By protocol, it should also be // BAD_VENDOR, but too many switch implementations // get it wrong and we can already check the xid() // so we can ignore the type with confidence that this // is not a spurious error shouldLogError = !isBadVendorError; if (isBadVendorError) { if (state.firstRoleReplyReceived && (role != null)) { log.warn("Received ERROR from sw {} that " +"indicates roles are not supported " +"but we have received a valid " +"role reply earlier", sw); } state.firstRoleReplyReceived = true; sw.deliverRoleRequestNotSupported(error.getXid()); synchronized(roleChanger) { if (sw.role == null && Controller.this.role==Role.SLAVE) { // the switch doesn't understand role request // messages and the current controller role is // slave. We need to disconnect the switch. // @see RoleChanger for rationale sw.getChannel().close(); } else if (sw.role == null) { // Controller's role is master: add to // active // TODO: check if clearing flow table is // right choice here. // Need to clear FlowMods before we add the switch // and dispatch updates otherwise we have a race condition. // TODO: switch update is async. Won't we still have a potential // race condition? sw.clearAllFlowMods(); addSwitch(sw); } } } else { // TODO: Is this the right thing to do if we receive // some other error besides a bad vendor error? // Presumably that means the switch did actually // understand the role request message, but there // was some other error from processing the message. // OF 1.2 specifies a OFPET_ROLE_REQUEST_FAILED // error code, but it doesn't look like the Nicira // role request has that. Should check OVS source // code to see if it's possible for any other errors // to be returned. // If we received an error the switch is not // in the correct role, so we need to disconnect it. // We could also resend the request but then we need to // check if there are other pending request in which // case we shouldn't resend. If we do resend we need // to make sure that the switch eventually accepts one // of our requests or disconnect the switch. This feels // cumbersome. sw.getChannel().close(); } } // Once we support OF 1.2, we'd add code to handle it here. //if (error.getXid() == state.ofRoleRequestXid) { //} if (shouldLogError) logError(sw, error); break; case STATS_REPLY: if (state.hsState.ordinal() < HandshakeState.FEATURES_REPLY.ordinal()) { String em = "Unexpected STATS_REPLY from " + sw; throw new SwitchStateException(em); } sw.deliverStatisticsReply(m); if (sw.hasAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE)) { processSwitchDescReply(); } break; case PORT_STATUS: // We want to update our port state info even if we're in // the slave role, but we only want to update storage if // we're the master (or equal). boolean updateStorage = state.hsState. equals(HandshakeState.READY) && (sw.getRole() != Role.SLAVE); handlePortStatusMessage(sw, (OFPortStatus)m, updateStorage); shouldHandleMessage = true; break; default: shouldHandleMessage = true; break; } if (shouldHandleMessage) { sw.getListenerReadLock().lock(); try { if (sw.isConnected()) { if (!state.hsState.equals(HandshakeState.READY)) { log.debug("Ignoring message type {} received " + "from switch {} before switch is " + "fully configured.", m.getType(), sw); } // Check if the controller is in the slave role for the // switch. If it is, then don't dispatch the message to // the listeners. // TODO: Should we dispatch messages that we expect to // receive when we're in the slave role, e.g. port // status messages? Since we're "hiding" switches from // the listeners when we're in the slave role, then it // seems a little weird to dispatch port status messages // to them. On the other hand there might be special // modules that care about all of the connected switches // and would like to receive port status notifications. else if (sw.getRole() == Role.SLAVE) { // Don't log message if it's a port status message // since we expect to receive those from the switch // and don't want to emit spurious messages. if (m.getType() != OFType.PORT_STATUS) { log.debug("Ignoring message type {} received " + "from switch {} while in the slave role.", m.getType(), sw); } } else { handleMessage(sw, m, null); } } } finally { sw.getListenerReadLock().unlock(); } } } } // **************** // Message handlers // **************** protected void handlePortStatusMessage(IOFSwitch sw, OFPortStatus m, boolean updateStorage) { short portNumber = m.getDesc().getPortNumber(); OFPhysicalPort port = m.getDesc(); if (m.getReason() == (byte)OFPortReason.OFPPR_MODIFY.ordinal()) { sw.setPort(port); if (updateStorage) updatePortInfo(sw, port); log.debug("Port #{} modified for {}", portNumber, sw); } else if (m.getReason() == (byte)OFPortReason.OFPPR_ADD.ordinal()) { sw.setPort(port); if (updateStorage) updatePortInfo(sw, port); log.debug("Port #{} added for {}", portNumber, sw); } else if (m.getReason() == (byte)OFPortReason.OFPPR_DELETE.ordinal()) { sw.deletePort(portNumber); if (updateStorage) removePortInfo(sw, portNumber); log.debug("Port #{} deleted for {}", portNumber, sw); } SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.PORTCHANGED); try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } /** * flcontext_cache - Keep a thread local stack of contexts */ protected static final ThreadLocal> flcontext_cache = new ThreadLocal > () { @Override protected Stack initialValue() { return new Stack(); } }; /** * flcontext_alloc - pop a context off the stack, if required create a new one * @return FloodlightContext */ protected static FloodlightContext flcontext_alloc() { FloodlightContext flcontext = null; if (flcontext_cache.get().empty()) { flcontext = new FloodlightContext(); } else { flcontext = flcontext_cache.get().pop(); } return flcontext; } /** * flcontext_free - Free the context to the current thread * @param flcontext */ protected void flcontext_free(FloodlightContext flcontext) { flcontext.getStorage().clear(); flcontext_cache.get().push(flcontext); } /** * Handle replies to certain OFMessages, and pass others off to listeners * @param sw The switch for the message * @param m The message * @param bContext The floodlight context. If null then floodlight context would * be allocated in this function * @throws IOException */ @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Ignoring PacketIn (Xid = {xid}) because the data" + " field is empty.", explanation="The switch sent an improperly-formatted PacketIn" + " message", recommendation=LogMessageDoc.CHECK_SWITCH), @LogMessageDoc(level="WARN", message="Unhandled OF Message: {} from {}", explanation="The switch sent a message not handled by " + "the controller") }) protected void handleMessage(IOFSwitch sw, OFMessage m, FloodlightContext bContext) throws IOException { Ethernet eth = null; switch (m.getType()) { case PACKET_IN: OFPacketIn pi = (OFPacketIn)m; if (pi.getPacketData().length <= 0) { log.error("Ignoring PacketIn (Xid = " + pi.getXid() + ") because the data field is empty."); return; } if (Controller.ALWAYS_DECODE_ETH) { eth = new Ethernet(); eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); counterStore.updatePacketInCounters(sw, m, eth); } // fall through to default case... default: List listeners = null; if (messageListeners.containsKey(m.getType())) { listeners = messageListeners.get(m.getType()). getOrderedListeners(); } FloodlightContext bc = null; if (listeners != null) { // Check if floodlight context is passed from the calling // function, if so use that floodlight context, otherwise // allocate one if (bContext == null) { bc = flcontext_alloc(); } else { bc = bContext; } if (eth != null) { IFloodlightProviderService.bcStore.put(bc, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, eth); } // Get the starting time (overall and per-component) of // the processing chain for this packet if performance // monitoring is turned on pktinProcTime.bootstrap(listeners); pktinProcTime.recordStartTimePktIn(); Command cmd; for (IOFMessageListener listener : listeners) { if (listener instanceof IOFSwitchFilter) { if (!((IOFSwitchFilter)listener).isInterested(sw)) { continue; } } pktinProcTime.recordStartTimeComp(listener); cmd = listener.receive(sw, m, bc); pktinProcTime.recordEndTimeComp(listener); if (Command.STOP.equals(cmd)) { break; } } pktinProcTime.recordEndTimePktIn(sw, m, bc); } else { log.warn("Unhandled OF Message: {} from {}", m, sw); } if ((bContext == null) && (bc != null)) flcontext_free(bc); } } /** * Log an OpenFlow error message from a switch * @param sw The switch that sent the error * @param error The error message */ @LogMessageDoc(level="ERROR", message="Error {error type} {error code} from {switch}", explanation="The switch responded with an unexpected error" + "to an OpenFlow message from the controller", recommendation="This could indicate improper network operation. " + "If the problem persists restarting the switch and " + "controller may help." ) protected void logError(IOFSwitch sw, OFError error) { int etint = 0xffff & error.getErrorType(); if (etint < 0 || etint >= OFErrorType.values().length) { log.error("Unknown error code {} from sw {}", etint, sw); } OFErrorType et = OFErrorType.values()[etint]; switch (et) { case OFPET_HELLO_FAILED: OFHelloFailedCode hfc = OFHelloFailedCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, hfc, sw}); break; case OFPET_BAD_REQUEST: OFBadRequestCode brc = OFBadRequestCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, brc, sw}); break; case OFPET_BAD_ACTION: OFBadActionCode bac = OFBadActionCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, bac, sw}); break; case OFPET_FLOW_MOD_FAILED: OFFlowModFailedCode fmfc = OFFlowModFailedCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, fmfc, sw}); break; case OFPET_PORT_MOD_FAILED: OFPortModFailedCode pmfc = OFPortModFailedCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, pmfc, sw}); break; case OFPET_QUEUE_OP_FAILED: OFQueueOpFailedCode qofc = OFQueueOpFailedCode.values()[0xffff & error.getErrorCode()]; log.error("Error {} {} from {}", new Object[] {et, qofc, sw}); break; default: break; } } /** * Add a switch to the active switch list and call the switch listeners. * This happens either when a switch first connects (and the controller is * not in the slave role) or when the role of the controller changes from * slave to master. * @param sw the switch that has been added */ // TODO: need to rethink locking and the synchronous switch update. // We can / should also handle duplicate DPIDs in connectedSwitches @LogMessageDoc(level="ERROR", message="New switch added {switch} for already-added switch {switch}", explanation="A switch with the same DPID as another switch " + "connected to the controller. This can be caused by " + "multiple switches configured with the same DPID, or " + "by a switch reconnected very quickly after " + "disconnecting.", recommendation="If this happens repeatedly, it is likely there " + "are switches with duplicate DPIDs on the network. " + "Reconfigure the appropriate switches. If it happens " + "very rarely, then it is likely this is a transient " + "network problem that can be ignored." ) protected void addSwitch(IOFSwitch sw) { // TODO: is it safe to modify the HashMap without holding // the old switch's lock? OFSwitchImpl oldSw = (OFSwitchImpl) this.activeSwitches.put(sw.getId(), sw); if (sw == oldSw) { // Note == for object equality, not .equals for value log.info("New add switch for pre-existing switch {}", sw); return; } if (oldSw != null) { oldSw.getListenerWriteLock().lock(); try { log.error("New switch added {} for already-added switch {}", sw, oldSw); // Set the connected flag to false to suppress calling // the listeners for this switch in processOFMessage oldSw.setConnected(false); oldSw.cancelAllStatisticsReplies(); updateInactiveSwitchInfo(oldSw); // we need to clean out old switch state definitively // before adding the new switch // FIXME: It seems not completely kosher to call the // switch listeners here. I thought one of the points of // having the asynchronous switch update mechanism was so // the addedSwitch and removedSwitch were always called // from a single thread to simplify concurrency issues // for the listener. if (switchListeners != null) { for (IOFSwitchListener listener : switchListeners) { listener.removedSwitch(oldSw); } } // will eventually trigger a removeSwitch(), which will cause // a "Not removing Switch ... already removed debug message. // TODO: Figure out a way to handle this that avoids the // spurious debug message. oldSw.getChannel().close(); } finally { oldSw.getListenerWriteLock().unlock(); } } updateActiveSwitchInfo(sw); SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.ADDED); try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } /** * Remove a switch from the active switch list and call the switch listeners. * This happens either when the switch is disconnected or when the * controller's role for the switch changes from master to slave. * @param sw the switch that has been removed */ protected void removeSwitch(IOFSwitch sw) { // No need to acquire the listener lock, since // this method is only called after netty has processed all // pending messages log.debug("removeSwitch: {}", sw); if (!this.activeSwitches.remove(sw.getId(), sw) || !sw.isConnected()) { log.debug("Not removing switch {}; already removed", sw); return; } // We cancel all outstanding statistics replies if the switch transition // from active. In the future we might allow statistics requests // from slave controllers. Then we need to move this cancelation // to switch disconnect sw.cancelAllStatisticsReplies(); // FIXME: I think there's a race condition if we call updateInactiveSwitchInfo // here if role support is enabled. In that case if the switch is being // removed because we've been switched to being in the slave role, then I think // it's possible that the new master may have already been promoted to master // and written out the active switch state to storage. If we now execute // updateInactiveSwitchInfo we may wipe out all of the state that was // written out by the new master. Maybe need to revisit how we handle all // of the switch state that's written to storage. updateInactiveSwitchInfo(sw); SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.REMOVED); try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } // *************** // IFloodlightProvider // *************** @Override public synchronized void addOFMessageListener(OFType type, IOFMessageListener listener) { ListenerDispatcher ldd = messageListeners.get(type); if (ldd == null) { ldd = new ListenerDispatcher(); messageListeners.put(type, ldd); } ldd.addListener(type, listener); } @Override public synchronized void removeOFMessageListener(OFType type, IOFMessageListener listener) { ListenerDispatcher ldd = messageListeners.get(type); if (ldd != null) { ldd.removeListener(listener); } } private void logListeners() { for (Map.Entry> entry : messageListeners.entrySet()) { OFType type = entry.getKey(); ListenerDispatcher ldd = entry.getValue(); StringBuffer sb = new StringBuffer(); sb.append("OFListeners for "); sb.append(type); sb.append(": "); for (IOFMessageListener l : ldd.getOrderedListeners()) { sb.append(l.getName()); sb.append(","); } log.debug(sb.toString()); } } public void removeOFMessageListeners(OFType type) { messageListeners.remove(type); } @Override public Map getSwitches() { return Collections.unmodifiableMap(this.activeSwitches); } @Override public void addOFSwitchListener(IOFSwitchListener listener) { this.switchListeners.add(listener); } @Override public void removeOFSwitchListener(IOFSwitchListener listener) { this.switchListeners.remove(listener); } @Override public Map> getListeners() { Map> lers = new HashMap>(); for(Entry> e : messageListeners.entrySet()) { lers.put(e.getKey(), e.getValue().getOrderedListeners()); } return Collections.unmodifiableMap(lers); } @Override @LogMessageDocs({ @LogMessageDoc(message="Failed to inject OFMessage {message} onto " + "a null switch", explanation="Failed to process a message because the switch " + " is no longer connected."), @LogMessageDoc(level="ERROR", message="Error reinjecting OFMessage on switch {switch}", explanation="An I/O error occured while attempting to " + "process an OpenFlow message", recommendation=LogMessageDoc.CHECK_SWITCH) }) public boolean injectOfMessage(IOFSwitch sw, OFMessage msg, FloodlightContext bc) { if (sw == null) { log.info("Failed to inject OFMessage {} onto a null switch", msg); return false; } // FIXME: Do we need to be able to inject messages to switches // where we're the slave controller (i.e. they're connected but // not active)? // FIXME: Don't we need synchronization logic here so we're holding // the listener read lock when we call handleMessage? After some // discussions it sounds like the right thing to do here would be to // inject the message as a netty upstream channel event so it goes // through the normal netty event processing, including being // handled if (!activeSwitches.containsKey(sw.getId())) return false; try { // Pass Floodlight context to the handleMessages() handleMessage(sw, msg, bc); } catch (IOException e) { log.error("Error reinjecting OFMessage on switch {}", HexString.toHexString(sw.getId())); return false; } return true; } @Override @LogMessageDoc(message="Calling System.exit", explanation="The controller is terminating") public synchronized void terminate() { log.info("Calling System.exit"); System.exit(1); } @Override public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) { // call the overloaded version with floodlight context set to null return injectOfMessage(sw, msg, null); } @Override public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) { if (log.isTraceEnabled()) { String str = OFMessage.getDataAsString(sw, m, bc); log.trace("{}", str); } List listeners = null; if (messageListeners.containsKey(m.getType())) { listeners = messageListeners.get(m.getType()).getOrderedListeners(); } if (listeners != null) { for (IOFMessageListener listener : listeners) { if (listener instanceof IOFSwitchFilter) { if (!((IOFSwitchFilter)listener).isInterested(sw)) { continue; } } if (Command.STOP.equals(listener.receive(sw, m, bc))) { break; } } } } @Override public BasicFactory getOFMessageFactory() { return factory; } @Override public String getControllerId() { return controllerId; } // ************** // Initialization // ************** protected void updateAllInactiveSwitchInfo() { if (role == Role.SLAVE) { return; } String controllerId = getControllerId(); String[] switchColumns = { SWITCH_DATAPATH_ID, SWITCH_CONTROLLER_ID, SWITCH_ACTIVE }; String[] portColumns = { PORT_ID, PORT_SWITCH }; IResultSet switchResultSet = null; try { OperatorPredicate op = new OperatorPredicate(SWITCH_CONTROLLER_ID, OperatorPredicate.Operator.EQ, controllerId); switchResultSet = storageSource.executeQuery(SWITCH_TABLE_NAME, switchColumns, op, null); while (switchResultSet.next()) { IResultSet portResultSet = null; try { String datapathId = switchResultSet.getString(SWITCH_DATAPATH_ID); switchResultSet.setBoolean(SWITCH_ACTIVE, Boolean.FALSE); op = new OperatorPredicate(PORT_SWITCH, OperatorPredicate.Operator.EQ, datapathId); portResultSet = storageSource.executeQuery(PORT_TABLE_NAME, portColumns, op, null); while (portResultSet.next()) { portResultSet.deleteRow(); } portResultSet.save(); } finally { if (portResultSet != null) portResultSet.close(); } } switchResultSet.save(); } finally { if (switchResultSet != null) switchResultSet.close(); } } protected void updateControllerInfo() { updateAllInactiveSwitchInfo(); // Write out the controller info to the storage source Map controllerInfo = new HashMap(); String id = getControllerId(); controllerInfo.put(CONTROLLER_ID, id); storageSource.updateRow(CONTROLLER_TABLE_NAME, controllerInfo); } protected void updateActiveSwitchInfo(IOFSwitch sw) { if (role == Role.SLAVE) { return; } // Obtain the row info for the switch Map switchInfo = new HashMap(); String datapathIdString = sw.getStringId(); switchInfo.put(SWITCH_DATAPATH_ID, datapathIdString); String controllerId = getControllerId(); switchInfo.put(SWITCH_CONTROLLER_ID, controllerId); Date connectedSince = sw.getConnectedSince(); switchInfo.put(SWITCH_CONNECTED_SINCE, connectedSince); Channel channel = sw.getChannel(); SocketAddress socketAddress = channel.getRemoteAddress(); if (socketAddress != null) { String socketAddressString = socketAddress.toString(); switchInfo.put(SWITCH_SOCKET_ADDRESS, socketAddressString); if (socketAddress instanceof InetSocketAddress) { InetSocketAddress inetSocketAddress = (InetSocketAddress)socketAddress; InetAddress inetAddress = inetSocketAddress.getAddress(); String ip = inetAddress.getHostAddress(); switchInfo.put(SWITCH_IP, ip); } } // Write out the switch features info long capabilities = U32.f(sw.getCapabilities()); switchInfo.put(SWITCH_CAPABILITIES, capabilities); long buffers = U32.f(sw.getBuffers()); switchInfo.put(SWITCH_BUFFERS, buffers); long tables = U32.f(sw.getTables()); switchInfo.put(SWITCH_TABLES, tables); long actions = U32.f(sw.getActions()); switchInfo.put(SWITCH_ACTIONS, actions); switchInfo.put(SWITCH_ACTIVE, Boolean.TRUE); // Update the switch storageSource.updateRowAsync(SWITCH_TABLE_NAME, switchInfo); // Update the ports for (OFPhysicalPort port: sw.getPorts()) { updatePortInfo(sw, port); } } protected void updateInactiveSwitchInfo(IOFSwitch sw) { if (role == Role.SLAVE) { return; } log.debug("Update DB with inactiveSW {}", sw); // Update the controller info in the storage source to be inactive Map switchInfo = new HashMap(); String datapathIdString = sw.getStringId(); switchInfo.put(SWITCH_DATAPATH_ID, datapathIdString); //switchInfo.put(SWITCH_CONNECTED_SINCE, null); switchInfo.put(SWITCH_ACTIVE, Boolean.FALSE); storageSource.updateRowAsync(SWITCH_TABLE_NAME, switchInfo); } protected void updatePortInfo(IOFSwitch sw, OFPhysicalPort port) { if (role == Role.SLAVE) { return; } String datapathIdString = sw.getStringId(); Map portInfo = new HashMap(); int portNumber = U16.f(port.getPortNumber()); String id = datapathIdString + "|" + portNumber; portInfo.put(PORT_ID, id); portInfo.put(PORT_SWITCH, datapathIdString); portInfo.put(PORT_NUMBER, portNumber); byte[] hardwareAddress = port.getHardwareAddress(); String hardwareAddressString = HexString.toHexString(hardwareAddress); portInfo.put(PORT_HARDWARE_ADDRESS, hardwareAddressString); String name = port.getName(); portInfo.put(PORT_NAME, name); long config = U32.f(port.getConfig()); portInfo.put(PORT_CONFIG, config); long state = U32.f(port.getState()); portInfo.put(PORT_STATE, state); long currentFeatures = U32.f(port.getCurrentFeatures()); portInfo.put(PORT_CURRENT_FEATURES, currentFeatures); long advertisedFeatures = U32.f(port.getAdvertisedFeatures()); portInfo.put(PORT_ADVERTISED_FEATURES, advertisedFeatures); long supportedFeatures = U32.f(port.getSupportedFeatures()); portInfo.put(PORT_SUPPORTED_FEATURES, supportedFeatures); long peerFeatures = U32.f(port.getPeerFeatures()); portInfo.put(PORT_PEER_FEATURES, peerFeatures); storageSource.updateRowAsync(PORT_TABLE_NAME, portInfo); } /** * Read switch port data from storage and write it into a switch object * @param sw the switch to update */ protected void readSwitchPortStateFromStorage(OFSwitchImpl sw) { OperatorPredicate op = new OperatorPredicate(PORT_SWITCH, OperatorPredicate.Operator.EQ, sw.getStringId()); IResultSet portResultSet = storageSource.executeQuery(PORT_TABLE_NAME, null, op, null); //Map oldports = // new HashMap(); //oldports.putAll(sw.getPorts()); while (portResultSet.next()) { try { OFPhysicalPort p = new OFPhysicalPort(); p.setPortNumber((short)portResultSet.getInt(PORT_NUMBER)); p.setName(portResultSet.getString(PORT_NAME)); p.setConfig((int)portResultSet.getLong(PORT_CONFIG)); p.setState((int)portResultSet.getLong(PORT_STATE)); String portMac = portResultSet.getString(PORT_HARDWARE_ADDRESS); p.setHardwareAddress(HexString.fromHexString(portMac)); p.setCurrentFeatures((int)portResultSet. getLong(PORT_CURRENT_FEATURES)); p.setAdvertisedFeatures((int)portResultSet. getLong(PORT_ADVERTISED_FEATURES)); p.setSupportedFeatures((int)portResultSet. getLong(PORT_SUPPORTED_FEATURES)); p.setPeerFeatures((int)portResultSet. getLong(PORT_PEER_FEATURES)); //oldports.remove(Short.valueOf(p.getPortNumber())); sw.setPort(p); } catch (NullPointerException e) { // ignore } } SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.PORTCHANGED); try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } protected void removePortInfo(IOFSwitch sw, short portNumber) { if (role == Role.SLAVE) { return; } String datapathIdString = sw.getStringId(); String id = datapathIdString + "|" + portNumber; storageSource.deleteRowAsync(PORT_TABLE_NAME, id); } /** * Sets the initial role based on properties in the config params. * It looks for two different properties. * If the "role" property is specified then the value should be * either "EQUAL", "MASTER", or "SLAVE" and the role of the * controller is set to the specified value. If the "role" property * is not specified then it looks next for the "role.path" property. * In this case the value should be the path to a property file in * the file system that contains a property called "floodlight.role" * which can be one of the values listed above for the "role" property. * The idea behind the "role.path" mechanism is that you have some * separate heartbeat and master controller election algorithm that * determines the role of the controller. When a role transition happens, * it updates the current role in the file specified by the "role.path" * file. Then if floodlight restarts for some reason it can get the * correct current role of the controller from the file. * @param configParams The config params for the FloodlightProvider service * @return A valid role if role information is specified in the * config params, otherwise null */ @LogMessageDocs({ @LogMessageDoc(message="Controller role set to {role}", explanation="Setting the initial HA role to "), @LogMessageDoc(level="ERROR", message="Invalid current role value: {role}", explanation="An invalid HA role value was read from the " + "properties file", recommendation=LogMessageDoc.CHECK_CONTROLLER) }) protected Role getInitialRole(Map configParams) { Role role = null; String roleString = configParams.get("role"); if (roleString == null) { String rolePath = configParams.get("rolepath"); if (rolePath != null) { Properties properties = new Properties(); try { properties.load(new FileInputStream(rolePath)); roleString = properties.getProperty("floodlight.role"); } catch (IOException exc) { // Don't treat it as an error if the file specified by the // rolepath property doesn't exist. This lets us enable the // HA mechanism by just creating/setting the floodlight.role // property in that file without having to modify the // floodlight properties. } } } if (roleString != null) { // Canonicalize the string to the form used for the enum constants roleString = roleString.trim().toUpperCase(); try { role = Role.valueOf(roleString); } catch (IllegalArgumentException exc) { log.error("Invalid current role value: {}", roleString); } } log.info("Controller role set to {}", role); return role; } /** * Tell controller that we're ready to accept switches loop * @throws IOException */ @LogMessageDocs({ @LogMessageDoc(message="Listening for switch connections on {address}", explanation="The controller is ready and listening for new" + " switch connections"), @LogMessageDoc(message="Storage exception in controller " + "updates loop; terminating process", explanation=ERROR_DATABASE, recommendation=LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Exception in controller updates loop", explanation="Failed to dispatch controller event", recommendation=LogMessageDoc.GENERIC_ACTION) }) public void run() { if (log.isDebugEnabled()) { logListeners(); } try { final ServerBootstrap bootstrap = createServerBootStrap(); bootstrap.setOption("reuseAddr", true); bootstrap.setOption("child.keepAlive", true); bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE); ChannelPipelineFactory pfact = new OpenflowPipelineFactory(this, null); bootstrap.setPipelineFactory(pfact); InetSocketAddress sa = new InetSocketAddress(openFlowPort); final ChannelGroup cg = new DefaultChannelGroup(); cg.add(bootstrap.bind(sa)); log.info("Listening for switch connections on {}", sa); } catch (Exception e) { throw new RuntimeException(e); } // main loop while (true) { try { IUpdate update = updates.take(); update.dispatch(); } catch (InterruptedException e) { return; } catch (StorageException e) { log.error("Storage exception in controller " + "updates loop; terminating process", e); return; } catch (Exception e) { log.error("Exception in controller updates loop", e); } } } private ServerBootstrap createServerBootStrap() { if (workerThreads == 0) { return new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); } else { return new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool(), workerThreads)); } } public void setConfigParams(Map configParams) { String ofPort = configParams.get("openflowport"); if (ofPort != null) { this.openFlowPort = Integer.parseInt(ofPort); } log.debug("OpenFlow port set to {}", this.openFlowPort); String threads = configParams.get("workerthreads"); if (threads != null) { this.workerThreads = Integer.parseInt(threads); } log.debug("Number of worker threads set to {}", this.workerThreads); String controllerId = configParams.get("controllerid"); if (controllerId != null) { this.controllerId = controllerId; } log.debug("ControllerId set to {}", this.controllerId); } private void initVendorMessages() { // Configure openflowj to be able to parse the role request/reply // vendor messages. OFBasicVendorId niciraVendorId = new OFBasicVendorId( OFNiciraVendorData.NX_VENDOR_ID, 4); OFVendorId.registerVendorId(niciraVendorId); OFBasicVendorDataType roleRequestVendorData = new OFBasicVendorDataType( OFRoleRequestVendorData.NXT_ROLE_REQUEST, OFRoleRequestVendorData.getInstantiable()); niciraVendorId.registerVendorDataType(roleRequestVendorData); OFBasicVendorDataType roleReplyVendorData = new OFBasicVendorDataType( OFRoleReplyVendorData.NXT_ROLE_REPLY, OFRoleReplyVendorData.getInstantiable()); niciraVendorId.registerVendorDataType(roleReplyVendorData); } /** * Initialize internal data structures */ public void init(Map configParams) { // These data structures are initialized here because other // module's startUp() might be called before ours this.messageListeners = new ConcurrentHashMap>(); this.switchListeners = new CopyOnWriteArraySet(); this.haListeners = new CopyOnWriteArraySet(); this.activeSwitches = new ConcurrentHashMap(); this.connectedSwitches = new HashSet(); this.controllerNodeIPsCache = new HashMap(); this.updates = new LinkedBlockingQueue(); this.factory = new BasicFactory(); this.providerMap = new HashMap>(); setConfigParams(configParams); this.role = getInitialRole(configParams); this.roleChanger = new RoleChanger(); initVendorMessages(); this.systemStartTime = System.currentTimeMillis(); } /** * Startup all of the controller's components */ @LogMessageDoc(message="Waiting for storage source", explanation="The system database is not yet ready", recommendation="If this message persists, this indicates " + "that the system database has failed to start. " + LogMessageDoc.CHECK_CONTROLLER) public void startupComponents() { // Create the table names we use storageSource.createTable(CONTROLLER_TABLE_NAME, null); storageSource.createTable(SWITCH_TABLE_NAME, null); storageSource.createTable(PORT_TABLE_NAME, null); storageSource.createTable(CONTROLLER_INTERFACE_TABLE_NAME, null); storageSource.createTable(SWITCH_CONFIG_TABLE_NAME, null); storageSource.setTablePrimaryKeyName(CONTROLLER_TABLE_NAME, CONTROLLER_ID); storageSource.setTablePrimaryKeyName(SWITCH_TABLE_NAME, SWITCH_DATAPATH_ID); storageSource.setTablePrimaryKeyName(PORT_TABLE_NAME, PORT_ID); storageSource.setTablePrimaryKeyName(CONTROLLER_INTERFACE_TABLE_NAME, CONTROLLER_INTERFACE_ID); storageSource.addListener(CONTROLLER_INTERFACE_TABLE_NAME, this); while (true) { try { updateControllerInfo(); break; } catch (StorageException e) { log.info("Waiting for storage source"); try { Thread.sleep(1000); } catch (InterruptedException e1) { } } } // Add our REST API restApi.addRestletRoutable(new CoreWebRoutable()); } @Override public void addInfoProvider(String type, IInfoProvider provider) { if (!providerMap.containsKey(type)) { providerMap.put(type, new ArrayList()); } providerMap.get(type).add(provider); } @Override public void removeInfoProvider(String type, IInfoProvider provider) { if (!providerMap.containsKey(type)) { log.debug("Provider type {} doesn't exist.", type); return; } providerMap.get(type).remove(provider); } public Map getControllerInfo(String type) { if (!providerMap.containsKey(type)) return null; Map result = new LinkedHashMap(); for (IInfoProvider provider : providerMap.get(type)) { result.putAll(provider.getInfo(type)); } return result; } @Override public void addHAListener(IHAListener listener) { this.haListeners.add(listener); } @Override public void removeHAListener(IHAListener listener) { this.haListeners.remove(listener); } /** * Handle changes to the controller nodes IPs and dispatch update. */ @SuppressWarnings("unchecked") protected void handleControllerNodeIPChanges() { HashMap curControllerNodeIPs = new HashMap(); HashMap addedControllerNodeIPs = new HashMap(); HashMap removedControllerNodeIPs =new HashMap(); String[] colNames = { CONTROLLER_INTERFACE_CONTROLLER_ID, CONTROLLER_INTERFACE_TYPE, CONTROLLER_INTERFACE_NUMBER, CONTROLLER_INTERFACE_DISCOVERED_IP }; synchronized(controllerNodeIPsCache) { // We currently assume that interface Ethernet0 is the relevant // controller interface. Might change. // We could (should?) implement this using // predicates, but creating the individual and compound predicate // seems more overhead then just checking every row. Particularly, // since the number of rows is small and changes infrequent IResultSet res = storageSource.executeQuery(CONTROLLER_INTERFACE_TABLE_NAME, colNames,null, null); while (res.next()) { if (res.getString(CONTROLLER_INTERFACE_TYPE).equals("Ethernet") && res.getInt(CONTROLLER_INTERFACE_NUMBER) == 0) { String controllerID = res.getString(CONTROLLER_INTERFACE_CONTROLLER_ID); String discoveredIP = res.getString(CONTROLLER_INTERFACE_DISCOVERED_IP); String curIP = controllerNodeIPsCache.get(controllerID); curControllerNodeIPs.put(controllerID, discoveredIP); if (curIP == null) { // new controller node IP addedControllerNodeIPs.put(controllerID, discoveredIP); } else if (curIP != discoveredIP) { // IP changed removedControllerNodeIPs.put(controllerID, curIP); addedControllerNodeIPs.put(controllerID, discoveredIP); } } } // Now figure out if rows have been deleted. We can't use the // rowKeys from rowsDeleted directly, since the tables primary // key is a compound that we can't disassemble Set curEntries = curControllerNodeIPs.keySet(); Set removedEntries = controllerNodeIPsCache.keySet(); removedEntries.removeAll(curEntries); for (String removedControllerID : removedEntries) removedControllerNodeIPs.put(removedControllerID, controllerNodeIPsCache.get(removedControllerID)); controllerNodeIPsCache = (HashMap) curControllerNodeIPs.clone(); HAControllerNodeIPUpdate update = new HAControllerNodeIPUpdate( curControllerNodeIPs, addedControllerNodeIPs, removedControllerNodeIPs); if (!removedControllerNodeIPs.isEmpty() || !addedControllerNodeIPs.isEmpty()) { try { this.updates.put(update); } catch (InterruptedException e) { log.error("Failure adding update to queue", e); } } } } @Override public Map getControllerNodeIPs() { // We return a copy of the mapping so we can guarantee that // the mapping return is the same as one that will be (or was) // dispatched to IHAListeners HashMap retval = new HashMap(); synchronized(controllerNodeIPsCache) { retval.putAll(controllerNodeIPsCache); } return retval; } @Override public void rowsModified(String tableName, Set rowKeys) { if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) { handleControllerNodeIPChanges(); } } @Override public void rowsDeleted(String tableName, Set rowKeys) { if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) { handleControllerNodeIPChanges(); } } @Override public long getSystemStartTime() { return (this.systemStartTime); } @Override public void setAlwaysClearFlowsOnSwAdd(boolean value) { this.alwaysClearFlowsOnSwAdd = value; } public boolean getAlwaysClearFlowsOnSwAdd() { return this.alwaysClearFlowsOnSwAdd; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java0000664000175000017500000000410112041336206032431 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.FrameDecoder; import org.openflow.protocol.OFMessage; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.OFMessageFactory; /** * Decode an openflow message from a Channel, for use in a netty * pipeline * @author readams */ public class OFMessageDecoder extends FrameDecoder { OFMessageFactory factory = new BasicFactory(); @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { if (!channel.isConnected()) { // In testing, I see decode being called AFTER decode last. // This check avoids that from reading curroupted frames return null; } List message = factory.parseMessage(buffer); return message; } @Override protected Object decodeLast(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { // This is not strictly needed atthis time. It is used to detect // connection reset detection from netty (for debug) return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java0000664000175000017500000007435012041336206031657 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.io.IOException; import java.net.SocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.util.TimedCache; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.ser.ToStringSerializer; import org.jboss.netty.channel.Channel; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFFeaturesRequest; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.OFVendor; import org.openflow.protocol.OFPhysicalPort.OFPortConfig; import org.openflow.protocol.OFPhysicalPort.OFPortState; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.statistics.OFDescriptionStatistics; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.util.HexString; import org.openflow.util.U16; import org.openflow.vendor.nicira.OFNiciraVendorData; import org.openflow.vendor.nicira.OFRoleRequestVendorData; import org.openflow.vendor.nicira.OFRoleVendorData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This is the internal representation of an openflow switch. */ public class OFSwitchImpl implements IOFSwitch { // TODO: should we really do logging in the class or should we throw // exception that can then be handled by callers? protected static Logger log = LoggerFactory.getLogger(OFSwitchImpl.class); private static final String HA_CHECK_SWITCH = "Check the health of the indicated switch. If the problem " + "persists or occurs repeatedly, it likely indicates a defect " + "in the switch HA implementation."; protected ConcurrentMap attributes; protected IFloodlightProviderService floodlightProvider; protected IThreadPoolService threadPool; protected Date connectedSince; protected String stringId; protected Channel channel; protected AtomicInteger transactionIdSource; // Lock to protect modification of the port maps. We only need to // synchronize on modifications. For read operations we are fine since // we rely on ConcurrentMaps which works for our use case. private Object portLock; // Map port numbers to the appropriate OFPhysicalPort protected ConcurrentHashMap portsByNumber; // Map port names to the appropriate OFPhyiscalPort // XXX: The OF spec doesn't specify if port names need to be unique but // according it's always the case in practice. protected ConcurrentHashMap portsByName; protected Map statsFutureMap; protected Map iofMsgListenersMap; protected Map featuresFutureMap; protected boolean connected; protected Role role; protected TimedCache timedCache; protected ReentrantReadWriteLock listenerLock; protected ConcurrentMap portBroadcastCacheHitMap; /** * When sending a role request message, the role request is added * to this queue. If a role reply is received this queue is checked to * verify that the reply matches the expected reply. We require in order * delivery of replies. That's why we use a Queue. * The RoleChanger uses a timeout to ensure we receive a timely reply. * * Need to synchronize on this instance if a request is sent, received, * checked. */ protected LinkedList pendingRoleRequests; /* Switch features from initial featuresReply */ protected int capabilities; protected int buffers; protected int actions; protected byte tables; protected long datapathId; public static IOFSwitchFeatures switchFeatures; protected static final ThreadLocal>> local_msg_buffer = new ThreadLocal>>() { @Override protected Map> initialValue() { return new HashMap>(); } }; // for managing our map sizes protected static final int MAX_MACS_PER_SWITCH = 1000; protected static class PendingRoleRequestEntry { protected int xid; protected Role role; // cookie is used to identify the role "generation". roleChanger uses protected long cookie; public PendingRoleRequestEntry(int xid, Role role, long cookie) { this.xid = xid; this.role = role; this.cookie = cookie; } } public OFSwitchImpl() { this.stringId = null; this.attributes = new ConcurrentHashMap(); this.connectedSince = new Date(); this.transactionIdSource = new AtomicInteger(); this.portLock = new Object(); this.portsByNumber = new ConcurrentHashMap(); this.portsByName = new ConcurrentHashMap(); this.connected = true; this.statsFutureMap = new ConcurrentHashMap(); this.featuresFutureMap = new ConcurrentHashMap(); this.iofMsgListenersMap = new ConcurrentHashMap(); this.role = null; this.timedCache = new TimedCache(100, 5*1000 ); // 5 seconds interval this.listenerLock = new ReentrantReadWriteLock(); this.portBroadcastCacheHitMap = new ConcurrentHashMap(); this.pendingRoleRequests = new LinkedList(); // Defaults properties for an ideal switch this.setAttribute(PROP_FASTWILDCARDS, OFMatch.OFPFW_ALL); this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, new Boolean(true)); this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, new Boolean(true)); } @Override public Object getAttribute(String name) { if (this.attributes.containsKey(name)) { return this.attributes.get(name); } return null; } @Override public void setAttribute(String name, Object value) { this.attributes.put(name, value); return; } @Override public Object removeAttribute(String name) { return this.attributes.remove(name); } @Override public boolean hasAttribute(String name) { return this.attributes.containsKey(name); } @Override @JsonIgnore public Channel getChannel() { return this.channel; } @JsonIgnore public void setChannel(Channel channel) { this.channel = channel; } @Override public void write(OFMessage m, FloodlightContext bc) throws IOException { Map> msg_buffer_map = local_msg_buffer.get(); List msg_buffer = msg_buffer_map.get(this); if (msg_buffer == null) { msg_buffer = new ArrayList(); msg_buffer_map.put(this, msg_buffer); } this.floodlightProvider.handleOutgoingMessage(this, m, bc); msg_buffer.add(m); if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) || ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) { this.write(msg_buffer); msg_buffer.clear(); } } @Override @LogMessageDoc(level="WARN", message="Sending OF message that modifies switch " + "state while in the slave role: {switch}", explanation="An application has sent a message to a switch " + "that is not valid when the switch is in a slave role", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) public void write(List msglist, FloodlightContext bc) throws IOException { for (OFMessage m : msglist) { if (role == Role.SLAVE) { switch (m.getType()) { case PACKET_OUT: case FLOW_MOD: case PORT_MOD: log.warn("Sending OF message that modifies switch " + "state while in the slave role: {}", m.getType().name()); break; default: break; } } this.floodlightProvider.handleOutgoingMessage(this, m, bc); } this.write(msglist); } public void write(List msglist) throws IOException { this.channel.write(msglist); } @Override public void disconnectOutputStream() { channel.close(); } @Override @JsonIgnore public void setFeaturesReply(OFFeaturesReply featuresReply) { synchronized(portLock) { if (stringId == null) { /* ports are updated via port status message, so we * only fill in ports on initial connection. */ for (OFPhysicalPort port : featuresReply.getPorts()) { setPort(port); } } this.datapathId = featuresReply.getDatapathId(); this.capabilities = featuresReply.getCapabilities(); this.buffers = featuresReply.getBuffers(); this.actions = featuresReply.getActions(); this.tables = featuresReply.getTables(); this.stringId = HexString.toHexString(this.datapathId); } } @Override @JsonIgnore public Collection getEnabledPorts() { List result = new ArrayList(); for (OFPhysicalPort port : portsByNumber.values()) { if (portEnabled(port)) { result.add(port); } } return result; } @Override @JsonIgnore public Collection getEnabledPortNumbers() { List result = new ArrayList(); for (OFPhysicalPort port : portsByNumber.values()) { if (portEnabled(port)) { result.add(port.getPortNumber()); } } return result; } @Override public OFPhysicalPort getPort(short portNumber) { return portsByNumber.get(portNumber); } @Override public OFPhysicalPort getPort(String portName) { return portsByName.get(portName); } @Override @JsonIgnore public void setPort(OFPhysicalPort port) { synchronized(portLock) { portsByNumber.put(port.getPortNumber(), port); portsByName.put(port.getName(), port); } } @Override @JsonProperty("ports") public Collection getPorts() { return Collections.unmodifiableCollection(portsByNumber.values()); } @Override public void deletePort(short portNumber) { synchronized(portLock) { portsByName.remove(portsByNumber.get(portNumber).getName()); portsByNumber.remove(portNumber); } } @Override public void deletePort(String portName) { synchronized(portLock) { portsByNumber.remove(portsByName.get(portName).getPortNumber()); portsByName.remove(portName); } } @Override public boolean portEnabled(short portNumber) { if (portsByNumber.get(portNumber) == null) return false; return portEnabled(portsByNumber.get(portNumber)); } @Override public boolean portEnabled(String portName) { if (portsByName.get(portName) == null) return false; return portEnabled(portsByName.get(portName)); } @Override public boolean portEnabled(OFPhysicalPort port) { if (port == null) return false; if ((port.getConfig() & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0) return false; if ((port.getState() & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0) return false; // Port STP state doesn't work with multiple VLANs, so ignore it for now //if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()) // return false; return true; } @Override @JsonSerialize(using=DPIDSerializer.class) @JsonProperty("dpid") public long getId() { if (this.stringId == null) throw new RuntimeException("Features reply has not yet been set"); return this.datapathId; } @JsonIgnore @Override public String getStringId() { return stringId; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "OFSwitchImpl [" + channel.getRemoteAddress() + " DPID[" + ((stringId != null) ? stringId : "?") + "]]"; } @Override public ConcurrentMap getAttributes() { return this.attributes; } @Override public Date getConnectedSince() { return connectedSince; } @JsonIgnore @Override public int getNextTransactionId() { return this.transactionIdSource.incrementAndGet(); } @Override public void sendStatsQuery(OFStatisticsRequest request, int xid, IOFMessageListener caller) throws IOException { request.setXid(xid); this.iofMsgListenersMap.put(xid, caller); List msglist = new ArrayList(1); msglist.add(request); this.channel.write(msglist); return; } @Override public Future> getStatistics(OFStatisticsRequest request) throws IOException { request.setXid(getNextTransactionId()); OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this, request.getXid()); this.statsFutureMap.put(request.getXid(), future); List msglist = new ArrayList(1); msglist.add(request); this.channel.write(msglist); return future; } @Override public void deliverStatisticsReply(OFMessage reply) { OFStatisticsFuture future = this.statsFutureMap.get(reply.getXid()); if (future != null) { future.deliverFuture(this, reply); // The future will ultimately unregister itself and call // cancelStatisticsReply return; } /* Transaction id was not found in statsFutureMap.check the other map */ IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid()); if (caller != null) { caller.receive(this, reply, null); } } @Override public void cancelStatisticsReply(int transactionId) { if (null == this.statsFutureMap.remove(transactionId)) { this.iofMsgListenersMap.remove(transactionId); } } @Override public void cancelAllStatisticsReplies() { /* we don't need to be synchronized here. Even if another thread * modifies the map while we're cleaning up the future will eventuall * timeout */ for (OFStatisticsFuture f : statsFutureMap.values()) { f.cancel(true); } statsFutureMap.clear(); iofMsgListenersMap.clear(); } /** * @param floodlightProvider the floodlightProvider to set */ @JsonIgnore public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { this.floodlightProvider = floodlightProvider; } @JsonIgnore public void setThreadPoolService(IThreadPoolService tp) { this.threadPool = tp; } @JsonIgnore @Override public synchronized boolean isConnected() { return connected; } @Override @JsonIgnore public synchronized void setConnected(boolean connected) { this.connected = connected; } @Override public Role getRole() { return role; } @JsonIgnore @Override public boolean isActive() { return (role != Role.SLAVE); } @Override @JsonIgnore public void setSwitchProperties(OFDescriptionStatistics description) { if (switchFeatures != null) { switchFeatures.setFromDescription(this, description); } } @Override @LogMessageDoc(level="ERROR", message="Failed to clear all flows on switch {switch}", explanation="An I/O error occured while trying to clear " + "flows on the switch.", recommendation=LogMessageDoc.CHECK_SWITCH) public void clearAllFlowMods() { // Delete all pre-existing flows OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL); OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory() .getMessage(OFType.FLOW_MOD)) .setMatch(match) .setCommand(OFFlowMod.OFPFC_DELETE) .setOutPort(OFPort.OFPP_NONE) .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); try { List msglist = new ArrayList(1); msglist.add(fm); channel.write(msglist); } catch (Exception e) { log.error("Failed to clear all flows on switch " + this, e); } } @Override public boolean updateBroadcastCache(Long entry, Short port) { if (timedCache.update(entry)) { Long count = portBroadcastCacheHitMap.putIfAbsent(port, new Long(1)); if (count != null) { count++; } return true; } else { return false; } } @Override @JsonIgnore public Map getPortBroadcastHits() { return this.portBroadcastCacheHitMap; } @Override public void flush() { Map> msg_buffer_map = local_msg_buffer.get(); List msglist = msg_buffer_map.get(this); if ((msglist != null) && (msglist.size() > 0)) { try { this.write(msglist); } catch (IOException e) { // TODO: log exception e.printStackTrace(); } msglist.clear(); } } public static void flush_all() { Map> msg_buffer_map = local_msg_buffer.get(); for (OFSwitchImpl sw : msg_buffer_map.keySet()) { sw.flush(); } } /** * Return a read lock that must be held while calling the listeners for * messages from the switch. Holding the read lock prevents the active * switch list from being modified out from under the listeners. * @return */ @JsonIgnore public Lock getListenerReadLock() { return listenerLock.readLock(); } /** * Return a write lock that must be held when the controllers modifies the * list of active switches. This is to ensure that the active switch list * doesn't change out from under the listeners as they are handling a * message from the switch. * @return */ @JsonIgnore public Lock getListenerWriteLock() { return listenerLock.writeLock(); } /** * Get the IP Address for the switch * @return the inet address */ @JsonSerialize(using=ToStringSerializer.class) public SocketAddress getInetAddress() { return channel.getRemoteAddress(); } /** * Send NX role request message to the switch requesting the specified role. * * This method should ONLY be called by @see RoleChanger.submitRequest(). * * After sending the request add it to the queue of pending request. We * use the queue to later verify that we indeed receive the correct reply. * @param sw switch to send the role request message to * @param role role to request * @param cookie an opaque value that will be stored in the pending queue so * RoleChanger can check for timeouts. * @return transaction id of the role request message that was sent */ protected int sendNxRoleRequest(Role role, long cookie) throws IOException { synchronized(pendingRoleRequests) { // Convert the role enum to the appropriate integer constant used // in the NX role request message int nxRole = 0; switch (role) { case EQUAL: nxRole = OFRoleVendorData.NX_ROLE_OTHER; break; case MASTER: nxRole = OFRoleVendorData.NX_ROLE_MASTER; break; case SLAVE: nxRole = OFRoleVendorData.NX_ROLE_SLAVE; break; default: log.error("Invalid Role specified for switch {}." + " Disconnecting.", this); // TODO: should throw an error return 0; } // Construct the role request message OFVendor roleRequest = (OFVendor)floodlightProvider. getOFMessageFactory().getMessage(OFType.VENDOR); int xid = this.getNextTransactionId(); roleRequest.setXid(xid); roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID); OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData(); roleRequestData.setRole(nxRole); roleRequest.setVendorData(roleRequestData); roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH + roleRequestData.getLength()); // Send it to the switch List msglist = new ArrayList(1); msglist.add(roleRequest); // FIXME: should this use this.write() in order for messages to // be processed by handleOutgoingMessage() this.channel.write(msglist); pendingRoleRequests.add(new PendingRoleRequestEntry(xid, role, cookie)); return xid; } } /** * Deliver a RoleReply message to this switch. Checks if the reply * message matches the expected reply (head of the pending request queue). * We require in-order delivery of replies. If there's any deviation from * our expectations we disconnect the switch. * * We must not check the received role against the controller's current * role because there's no synchronization but that's fine @see RoleChanger * * Will be called by the OFChannelHandler's receive loop * * @param xid Xid of the reply message * @param role The Role in the the reply message */ @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Switch {switch}: received unexpected role reply for " + "Role {role}" + " Disconnecting switch", explanation="The switch sent an unexpected HA role reply", recommendation=HA_CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Switch {switch}: expected role reply with " + "Xid {xid}, got {xid}. Disconnecting switch", explanation="The switch sent an unexpected HA role reply", recommendation=HA_CHECK_SWITCH), @LogMessageDoc(level="ERROR", message="Switch {switch}: expected role reply with " + "Role {role}, got {role}. Disconnecting switch", explanation="The switch sent an unexpected HA role reply", recommendation=HA_CHECK_SWITCH) }) protected void deliverRoleReply(int xid, Role role) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.poll(); if (head == null) { // Maybe don't disconnect if the role reply we received is // for the same role we are already in. log.error("Switch {}: received unexpected role reply for Role {}" + " Disconnecting switch", this, role ); this.channel.close(); } else if (head.xid != xid) { // check xid before role!! log.error("Switch {}: expected role reply with " + "Xid {}, got {}. Disconnecting switch", new Object[] { this, head.xid, xid } ); this.channel.close(); } else if (head.role != role) { log.error("Switch {}: expected role reply with " + "Role {}, got {}. Disconnecting switch", new Object[] { this, head.role, role } ); this.channel.close(); } else { log.debug("Received role reply message from {}, setting role to {}", this, role); if (this.role == null && getAttribute(SWITCH_SUPPORTS_NX_ROLE) == null) { // The first role reply we received. Set the attribute // that the switch supports roles setAttribute(SWITCH_SUPPORTS_NX_ROLE, true); } this.role = role; } } } /** * Checks whether the given xid matches the xid of the first pending * role request. * @param xid * @return */ protected boolean checkFirstPendingRoleRequestXid (int xid) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.peek(); if (head == null) return false; else return head.xid == xid; } } /** * Checks whether the given request cookie matches the cookie of the first * pending request * @param cookie * @return */ protected boolean checkFirstPendingRoleRequestCookie(long cookie) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.peek(); if (head == null) return false; else return head.cookie == cookie; } } /** * Called if we receive a vendor error message indicating that roles * are not supported by the switch. If the xid matches the first pending * one, we'll mark the switch as not supporting roles and remove the head. * Otherwise we ignore it. * @param xid */ protected void deliverRoleRequestNotSupported(int xid) { synchronized(pendingRoleRequests) { PendingRoleRequestEntry head = pendingRoleRequests.poll(); this.role = null; if (head!=null && head.xid == xid) { setAttribute(SWITCH_SUPPORTS_NX_ROLE, false); } else { this.channel.close(); } } } @Override public Future getFeaturesReplyFromSwitch() throws IOException { OFMessage request = new OFFeaturesRequest(); request.setXid(getNextTransactionId()); OFFeaturesReplyFuture future = new OFFeaturesReplyFuture(threadPool, this, request.getXid()); this.featuresFutureMap.put(request.getXid(), future); List msglist = new ArrayList(1); msglist.add(request); this.channel.write(msglist); return future; } @Override public void deliverOFFeaturesReply(OFMessage reply) { OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid()); if (future != null) { future.deliverFuture(this, reply); // The future will ultimately unregister itself and call // cancelFeaturesReply return; } log.error("Switch {}: received unexpected featureReply", this); } @Override public void cancelFeaturesReply(int transactionId) { this.featuresFutureMap.remove(transactionId); } @Override public int getBuffers() { return buffers; } @Override public int getActions() { return actions; } @Override public int getCapabilities() { return capabilities; } @Override public byte getTables() { return tables; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java0000664000175000017500000000075512041336206032401 0ustar jamespagejamespagepackage net.floodlightcontroller.core.internal; import org.kohsuke.args4j.Option; /** * Expresses the port settings of OpenFlow controller. */ public class CmdLineSettings { public static final String DEFAULT_CONFIG_FILE = "config/floodlight.properties"; @Option(name="-cf", aliases="--configFile", metaVar="FILE", usage="Floodlight configuration file") private String configFile = DEFAULT_CONFIG_FILE; public String getModuleFile() { return configFile; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java0000664000175000017500000000472512041336206033120 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFStatisticsReply; import org.openflow.protocol.OFType; import org.openflow.protocol.statistics.OFStatistics; /** * A concrete implementation that handles asynchronously receiving OFStatistics * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFStatisticsFuture extends OFMessageFuture> { protected volatile boolean finished; public OFStatisticsFuture(IThreadPoolService tp, IOFSwitch sw, int transactionId) { super(tp, sw, OFType.STATS_REPLY, transactionId); init(); } public OFStatisticsFuture(IThreadPoolService tp, IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) { super(tp, sw, OFType.STATS_REPLY, transactionId, timeout, unit); init(); } private void init() { this.finished = false; this.result = new CopyOnWriteArrayList(); } @Override protected void handleReply(IOFSwitch sw, OFMessage msg) { OFStatisticsReply sr = (OFStatisticsReply) msg; synchronized (this.result) { this.result.addAll(sr.getStatistics()); if ((sr.getFlags() & 0x1) == 0) { this.finished = true; } } } @Override protected boolean isFinished() { return finished; } @Override protected void unRegister() { super.unRegister(); sw.cancelStatisticsReply(transactionId); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutException.java0000664000175000017500000000174112041336206034455 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; /** * Exception is thrown when the handshake fails to complete * before a specified time * @author readams */ public class HandshakeTimeoutException extends Exception { private static final long serialVersionUID = 6859880268940337312L; } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java0000664000175000017500000000406712041336206033557 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; /** * A concrete implementation that handles asynchronously receiving * OFFeaturesReply * * @author Shudong Zhou */ public class OFFeaturesReplyFuture extends OFMessageFuture { protected volatile boolean finished; public OFFeaturesReplyFuture(IThreadPoolService tp, IOFSwitch sw, int transactionId) { super(tp, sw, OFType.FEATURES_REPLY, transactionId); init(); } public OFFeaturesReplyFuture(IThreadPoolService tp, IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) { super(tp, sw, OFType.FEATURES_REPLY, transactionId, timeout, unit); init(); } private void init() { this.finished = false; this.result = null; } @Override protected void handleReply(IOFSwitch sw, OFMessage msg) { this.result = (OFFeaturesReply) msg; this.finished = true; } @Override protected boolean isFinished() { return finished; } @Override protected void unRegister() { super.unRegister(); sw.cancelFeaturesReply(transactionId); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/SwitchStateException.java0000664000175000017500000000225312041336206033461 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; /** * */ public class SwitchStateException extends Exception { private static final long serialVersionUID = 9153954512470002631L; public SwitchStateException() { super(); } public SwitchStateException(String arg0, Throwable arg1) { super(arg0, arg1); } public SwitchStateException(String arg0) { super(arg0); } public SwitchStateException(Throwable arg0) { super(arg0); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java0000664000175000017500000000044212041336206032634 0ustar jamespagejamespagepackage net.floodlightcontroller.core.internal; import org.openflow.protocol.statistics.OFDescriptionStatistics; import net.floodlightcontroller.core.IOFSwitch; public interface IOFSwitchFeatures { public void setFromDescription(IOFSwitch sw, OFDescriptionStatistics description); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java0000664000175000017500000003751112041336206031536 0ustar jamespagejamespagepackage net.floodlightcontroller.core.internal; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageDoc; /** * This class handles sending of RoleRequest messages to all connected switches. * * Handling Role Requests is tricky. Roles are hard state on the switch and * we can't query it so we need to make sure that we have consistent states * on the switches. Whenever we send a role request to the set of connected * switches we need to make sure that we've sent the request to all of them * before we process the next change request. If a new switch connects, we * need to send it the current role and need to make sure that the current * role doesn't change while we are doing it. We achieve this by synchronizing * all these actions on Controller.roleChanger * On the receive side: we need to make sure that we receive a reply for each * request we send and that the reply is consistent with the request we sent. * We'd also like to send the role request to the switch asynchronously in a * separate thread so we don't block the REST API or other callers. * * There are potential ways to relax these synchronization requirements: * - "Generation ID" for each role request. However, this would be most useful * if it were global for the whole cluster * - Regularly resend the controller's current role. Don't know whether this * might have adverse effects on the switch. * * Caveats: * - No way to know if another controller (not in our controller cluster) * sends MASTER requests to connected switches. Then we would drop to * slave role without knowing it. Could regularly resend the current role. * Ideally the switch would notify us if it demoted us. What happens if * the other controller also regularly resends the same role request? * Or if the health check determines that * a controller is dead but the controller is still talking to switches (maybe * just its health check failed) and resending the master role request.... * We could try to detect if a switch demoted us to slave even if we think * we are master (error messages on packet outs, e.g., when sending LLDPs) * * * The general model of Role Request handling is as follows: * * - All role request messages are handled by this class. Class Controller * submits a role change request and the request gets queued. submitRequest * takes a Collection of switches to which to send the request. We make a copy * of this list. * - A thread takes these change requests from the queue and sends them to * all the switches (using our copy of the switch list). * - The OFSwitchImpl sends the request over the wire and puts the request * into a queue of pending request (storing xid and role). We start a timeout * to make sure we eventually receive a reply from the switch. We use a single * timeout for each request submitted using submitRequest() * - After the timeout triggers we go over the list of switches again and * check that a response has been received (by checking the head of the * OFSwitchImpl's queue of pending requests) * - We handle requests and timeouts in the same thread. We use a priority queue * to schedule them so we are guaranteed that they are processed in * the same order as they are submitted. If a request times out we drop * the connection to this switch. * - Since we decouple submission of role change requests and actually sending * them we cannot check a received role reply against the controller's current * role because the controller's current role could have changed again. * - Receiving Role Reply messages is handled by OFChannelHandler and * OFSwitchImpl directly. The OFSwitchImpl checks if the received request * is as expected (xid and role match the head of the pending queue in * OFSwitchImpl). If so * the switch updates its role. Otherwise the connection is dropped. If this * is the first reply, the SWITCH_SUPPORTS_NX_ROLE attribute is set. * Next, we call addSwitch(), removeSwitch() to update the list of active * switches if appropriate. * - If we receive an Error indicating that roles are not supported by the * switch, we set the SWITCH_SUPPORTS_NX_ROLE to false. We keep the * switch connection alive while in MASTER and EQUAL role. * (TODO: is this the right behavior for EQUAL??). If the role changes to * SLAVE the switch connection is dropped (remember: only if the switch * doesn't support role requests) * The expected behavior is that the switch will probably try to reconnect * repeatedly (with some sort of exponential backoff), but after a while * will give-up and move on to the next controller-IP configured on the * switch. This is the serial failover mechanism from OpenFlow spec v1.0. * * New switch connection: * - Switch handshake is done without sending any role request messages. * - After handshake completes, switch is added to the list of connected switches * and we send the first role request message if role * requests are enabled. If roles are disabled automatically promote switch to * active switch list and clear FlowTable. * - When we receive the first reply we proceed as above. In addition, if * the role request is for MASTER we wipe the flow table. We do not wipe * the flow table if the switch connected while role supported was disabled * on the controller. * */ public class RoleChanger { // FIXME: Upon closer inspection DelayQueue seems to be somewhat broken. // We are required to implement a compareTo based on getDelay() and // getDelay() must return the remaining delay, thus it needs to use the // current time. So x1.compareTo(x1) can never return 0 as some time // will have passed between evaluating both getDelays(). This is even worse // if the thread happens to be preempted between calling the getDelay() // For the time being we enforce a small delay between subsequent // role request messages and hope that's long enough to not screw up // ordering. In the long run we might want to use two threads and two queues // (one for requests, one for timeouts) // Sigh. protected DelayQueue pendingTasks; protected long lastSubmitTime; protected Thread workerThread; protected long timeout; protected static long DEFAULT_TIMEOUT = 15L*1000*1000*1000L; // 15s protected static Logger log = LoggerFactory.getLogger(RoleChanger.class); /** * A queued task to be handled by the Role changer thread. */ protected static class RoleChangeTask implements Delayed { protected enum Type { /** This is a request. Dispatch the role update to switches */ REQUEST, /** This is a timeout task. Check if all switches have correctly replied to the previously dispatched role request */ TIMEOUT } // The set of switches to work on public Collection switches; public Role role; public Type type; // the time when the task should run as nanoTime() public long deadline; public RoleChangeTask(Collection switches, Role role, long deadline) { this.switches = switches; this.role = role; this.type = Type.REQUEST; this.deadline = deadline; } @Override public int compareTo(Delayed o) { Long timeRemaining = getDelay(TimeUnit.NANOSECONDS); return timeRemaining.compareTo(o.getDelay(TimeUnit.NANOSECONDS)); } @Override public long getDelay(TimeUnit tu) { long timeRemaining = deadline - System.nanoTime(); return tu.convert(timeRemaining, TimeUnit.NANOSECONDS); } } @LogMessageDoc(level="ERROR", message="RoleRequestWorker task had an uncaught exception.", explanation="An unknown occured while processing an HA " + "role change event.", recommendation=LogMessageDoc.GENERIC_ACTION) protected class RoleRequestWorker extends Thread { @Override public void run() { RoleChangeTask t; boolean interrupted = false; log.trace("RoleRequestWorker thread started"); try { while (true) { try { t = pendingTasks.take(); } catch (InterruptedException e) { // see http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html interrupted = true; continue; } if (t.type == RoleChangeTask.Type.REQUEST) { sendRoleRequest(t.switches, t.role, t.deadline); // Queue the timeout t.type = RoleChangeTask.Type.TIMEOUT; t.deadline += timeout; pendingTasks.put(t); } else { verifyRoleReplyReceived(t.switches, t.deadline); } } } catch (Exception e) { // Should never get here log.error("RoleRequestWorker task had an uncaught exception. ", e); } finally { // Be nice in case we earlier caught InterruptedExecution if (interrupted) Thread.currentThread().interrupt(); } } // end loop } public RoleChanger() { this.pendingTasks = new DelayQueue(); this.workerThread = new Thread(new RoleRequestWorker()); this.timeout = DEFAULT_TIMEOUT; this.workerThread.start(); } public synchronized void submitRequest(Collection switches, Role role) { long deadline = System.nanoTime(); // Grrr. stupid DelayQueue. Make sre we have at least 10ms between // role request messages. if (deadline - lastSubmitTime < 10 * 1000*1000) deadline = lastSubmitTime + 10 * 1000*1000; // make a copy of the list ArrayList switches_copy = new ArrayList(switches); RoleChangeTask req = new RoleChangeTask(switches_copy, role, deadline); pendingTasks.put(req); lastSubmitTime = deadline; } /** * Send a role request message to switches. This checks the capabilities * of the switch for understanding role request messaging. Currently we only * support the OVS-style role request message, but once the controller * supports OF 1.2, this function will also handle sending out the * OF 1.2-style role request message. * @param switches the collection of switches to send the request too * @param role the role to request */ @LogMessageDoc(level="WARN", message="Failed to send role request message " + "to switch {switch}: {message}. Disconnecting", explanation="An I/O error occurred while attempting to change " + "the switch HA role.", recommendation=LogMessageDoc.CHECK_SWITCH) protected void sendRoleRequest(Collection switches, Role role, long cookie) { // There are three cases to consider: // // 1) If the controller role at the point the switch connected was // null/disabled, then we never sent the role request probe to the // switch and therefore never set the SWITCH_SUPPORTS_NX_ROLE // attribute for the switch, so supportsNxRole is null. In that // case since we're now enabling role support for the controller // we should send out the role request probe/update to the switch. // // 2) If supportsNxRole == Boolean.TRUE then that means we've already // sent the role request probe to the switch and it replied with // a role reply message, so we know it supports role request // messages. Now we're changing the role and we want to send // it another role request message to inform it of the new role // for the controller. // // 3) If supportsNxRole == Boolean.FALSE, then that means we sent the // role request probe to the switch but it responded with an error // indicating that it didn't understand the role request message. // In that case we don't want to send it another role request that // it (still) doesn't understand. But if the new role of the // controller is SLAVE, then we don't want the switch to remain // connected to this controller. It might support the older serial // failover model for HA support, so we want to terminate the // connection and get it to initiate a connection with another // controller in its list of controllers. Eventually (hopefully, if // things are configured correctly) it will walk down its list of // controllers and connect to the current master controller. Iterator iter = switches.iterator(); while(iter.hasNext()) { OFSwitchImpl sw = iter.next(); try { Boolean supportsNxRole = (Boolean) sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE); if ((supportsNxRole == null) || supportsNxRole) { // Handle cases #1 and #2 sw.sendNxRoleRequest(role, cookie); } else { // Handle case #3 if (role == Role.SLAVE) { log.debug("Disconnecting switch {} that doesn't support " + "role request messages from a controller that went to SLAVE mode"); // Closing the channel should result in a call to // channelDisconnect which updates all state sw.getChannel().close(); iter.remove(); } } } catch (IOException e) { log.warn("Failed to send role request message " + "to switch {}: {}. Disconnecting", sw, e); sw.getChannel().close(); iter.remove(); } } } /** * Verify that switches have received a role reply message we sent earlier * @param switches the collection of switches to send the request too * @param cookie the cookie of the request */ @LogMessageDoc(level="WARN", message="Timeout while waiting for role reply from switch {switch}." + " Disconnecting", explanation="Timed out waiting for the switch to respond to " + "a request to change the HA role.", recommendation=LogMessageDoc.CHECK_SWITCH) protected void verifyRoleReplyReceived(Collection switches, long cookie) { for (OFSwitchImpl sw: switches) { if (sw.checkFirstPendingRoleRequestCookie(cookie)) { sw.getChannel().close(); log.warn("Timeout while waiting for role reply from switch {}." + " Disconnecting", sw); } } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java0000664000175000017500000004716012041336206032004 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFType; import org.openflow.util.HexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.ArrayList; import org.apache.thrift.TException; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packetstreamer.thrift.*; import net.floodlightcontroller.threadpool.IThreadPoolService; @LogMessageCategory("OpenFlow Message Tracing") public class OFMessageFilterManager implements IOFMessageListener, IFloodlightModule, IOFMessageFilterManagerService { /** * @author Srini */ protected static Logger log = LoggerFactory.getLogger(OFMessageFilterManager.class); // The port and client reference for packet streaming protected int serverPort = 9090; protected final int MaxRetry = 1; protected static TTransport transport = null; protected static PacketStreamer.Client packetClient = null; protected IFloodlightProviderService floodlightProvider = null; protected IThreadPoolService threadPool = null; // filter List is a key value pair. Key is the session id, // value is the filter rules. protected ConcurrentHashMap> filterMap = null; protected ConcurrentHashMap filterTimeoutMap = null; protected Timer timer = null; protected int MAX_FILTERS=5; protected long MAX_FILTER_TIME= 300000; // maximum filter time is 5 minutes. protected int TIMER_INTERVAL = 1000; // 1 second time interval. public static final String SUCCESS = "0"; public static final String FILTER_SETUP_FAILED = "-1001"; public static final String FILTER_NOT_FOUND = "-1002"; public static final String FILTER_LIMIT_REACHED = "-1003"; public static final String FILTER_SESSION_ID_NOT_FOUND = "-1004"; public static final String SERVICE_UNAVAILABLE = "-1005"; public enum FilterResult { /* * FILTER_NOT_DEFINED: Filter is not defined * FILTER_NO_MATCH: Filter is defined and the packet doesn't * match the filter * FILTER_MATCH: Filter is defined and the packet matches * the filter */ FILTER_NOT_DEFINED, FILTER_NO_MATCH, FILTER_MATCH } protected String addFilter(ConcurrentHashMap f, long delta) { // Create unique session ID. int prime = 33791; String s = null; int i; if ((filterMap == null) || (filterTimeoutMap == null)) return String.format("%d", FILTER_SETUP_FAILED); for (i=0; i f, int deltaInMilliSeconds) { if (sid == null) { // Delta in filter needs to be milliseconds log.debug("Adding new filter: {} for {} ms", f, deltaInMilliSeconds); return addFilter(f, deltaInMilliSeconds); } else {// this is the session id. // we will ignore the hash map features. if (deltaInMilliSeconds > 0) return refreshFilter(sid, deltaInMilliSeconds); else return deleteFilter(sid); } } public int timeoutFilters() { Iterator i = filterTimeoutMap.keySet().iterator(); while(i.hasNext()) { String s = i.next(); Long t = filterTimeoutMap.get(s); if (t != null) { i.remove(); t -= TIMER_INTERVAL; if (t > 0) { filterTimeoutMap.put(s, t); } else deleteFilter(s); } else deleteFilter(s); } return filterMap.size(); } protected String refreshFilter(String s, int delta) { Long t = filterTimeoutMap.get(s); if (t != null) { filterTimeoutMap.remove(s); t += delta; // time is in milliseconds if (t > MAX_FILTER_TIME) t = MAX_FILTER_TIME; filterTimeoutMap.put(s, t); return SUCCESS; } else return FILTER_SESSION_ID_NOT_FOUND; } @LogMessageDoc(level="ERROR", message="Error while terminating packet " + "filter session", explanation="An unknown error occurred while terminating " + "a packet filter session.", recommendation=LogMessageDoc.GENERIC_ACTION) protected String deleteFilter(String sessionId) { if (filterMap.containsKey(sessionId)) { filterMap.remove(sessionId); try { if (packetClient != null) packetClient.terminateSession(sessionId); } catch (TException e) { log.error("Error while terminating packet " + "filter session", e); } log.debug("Deleted Filter {}. # of filters" + " remaining: {}", sessionId, filterMap.size()); return SUCCESS; } else return FILTER_SESSION_ID_NOT_FOUND; } public HashSet getMatchedFilters(OFMessage m, FloodlightContext cntx) { HashSet matchedFilters = new HashSet(); // This default function is written to match on packet ins and // packet outs. Ethernet eth = null; if (m.getType() == OFType.PACKET_IN) { eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); } else if (m.getType() == OFType.PACKET_OUT) { eth = new Ethernet(); OFPacketOut p = (OFPacketOut) m; // No MAC match if packetOut doesn't have the packet. if (p.getPacketData() == null) return null; eth.deserialize(p.getPacketData(), 0, p.getPacketData().length); } else if (m.getType() == OFType.FLOW_MOD) { // flow-mod can't be matched by mac. return null; } if (eth == null) return null; Iterator filterIt = filterMap.keySet().iterator(); while (filterIt.hasNext()) { // for every filter boolean filterMatch = false; String filterSessionId = filterIt.next(); Map filter = filterMap.get(filterSessionId); // If the filter has empty fields, then it is not considered as a match. if (filter == null || filter.isEmpty()) continue; Iterator fieldIt = filter.keySet().iterator(); while (fieldIt.hasNext()) { String filterFieldType = fieldIt.next(); String filterFieldValue = filter.get(filterFieldType); if (filterFieldType.equals("mac")) { String srcMac = HexString.toHexString(eth.getSourceMACAddress()); String dstMac = HexString.toHexString(eth.getDestinationMACAddress()); log.debug("srcMac: {}, dstMac: {}", srcMac, dstMac); if (filterFieldValue.equals(srcMac) || filterFieldValue.equals(dstMac)){ filterMatch = true; } else { filterMatch = false; break; } } } if (filterMatch) { matchedFilters.add(filterSessionId); } } if (matchedFilters.isEmpty()) return null; else return matchedFilters; } @LogMessageDoc(level="ERROR", message="Failed to establish connection with the " + "packetstreamer server.", explanation="The message tracing server is not running " + "or otherwise unavailable.", recommendation=LogMessageDoc.CHECK_CONTROLLER) public boolean connectToPSServer() { int numRetries = 0; if (transport != null && transport.isOpen()) { return true; } while (numRetries++ < MaxRetry) { try { transport = new TFramedTransport(new TSocket("localhost", serverPort)); transport.open(); TProtocol protocol = new TBinaryProtocol(transport); packetClient = new PacketStreamer.Client(protocol); log.debug("Have a connection to packetstreamer server " + "localhost:{}", serverPort); break; } catch (TException x) { try { // Wait for 1 second before retry if (numRetries < MaxRetry) { Thread.sleep(1000); } } catch (Exception e) {} } } if (numRetries > MaxRetry) { log.error("Failed to establish connection with the " + "packetstreamer server."); return false; } return true; } public void disconnectFromPSServer() { if (transport != null && transport.isOpen()) { log.debug("Close the connection to packetstreamer server" + " localhost:{}", serverPort); transport.close(); } } @Override public String getName() { return "messageFilterManager"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return (type == OFType.PACKET_IN && name.equals("devicemanager")); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return (type == OFType.PACKET_IN && name.equals("learningswitch")); } @Override @LogMessageDoc(level="ERROR", message="Error while sending packet", explanation="Failed to send a message to the message " + "tracing server", recommendation=LogMessageDoc.CHECK_CONTROLLER) public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { if (filterMap == null || filterMap.isEmpty()) return Command.CONTINUE; HashSet matchedFilters = null; if (log.isDebugEnabled()) { log.debug("Received packet {} from switch {}", msg, sw.getStringId()); } matchedFilters = getMatchedFilters(msg, cntx); if (matchedFilters == null) { return Command.CONTINUE; } else { try { sendPacket(matchedFilters, sw, msg, cntx, true); } catch (Exception e) { log.error("Error while sending packet", e); } } return Command.CONTINUE; } public class TimeoutFilterTask extends TimerTask { OFMessageFilterManager filterManager; ScheduledExecutorService ses = threadPool.getScheduledExecutor(); public TimeoutFilterTask(OFMessageFilterManager manager) { filterManager = manager; } public void run() { int x = filterManager.timeoutFilters(); if (x > 0) { // there's at least one filter still active. Timer timer = new Timer(); timer.schedule(new TimeoutFilterTask(filterManager), TIMER_INTERVAL); } else { // Don't stop the listener to avoid race condition //stopListening(); } } } public int getNumberOfFilters() { return filterMap.size(); } public int getMaxFilterSize() { return MAX_FILTERS; } protected void sendPacket(HashSet matchedFilters, IOFSwitch sw, OFMessage msg, FloodlightContext cntx, boolean sync) throws TException { Message sendMsg = new Message(); Packet packet = new Packet(); ChannelBuffer bb; sendMsg.setPacket(packet); List sids = new ArrayList(matchedFilters); sendMsg.setSessionIDs(sids); packet.setMessageType(OFMessageType.findByValue((msg.getType().ordinal()))); switch (msg.getType()) { case PACKET_IN: OFPacketIn pktIn = (OFPacketIn)msg; packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), pktIn.getInPort())); bb = ChannelBuffers.buffer(pktIn.getLength()); pktIn.writeTo(bb); packet.setData(OFMessage.getData(sw, msg, cntx)); break; case PACKET_OUT: OFPacketOut pktOut = (OFPacketOut)msg; packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), pktOut.getInPort())); bb = ChannelBuffers.buffer(pktOut.getLength()); pktOut.writeTo(bb); packet.setData(OFMessage.getData(sw, msg, cntx)); break; case FLOW_MOD: OFFlowMod offlowMod = (OFFlowMod)msg; packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), offlowMod. getOutPort())); bb = ChannelBuffers.buffer(offlowMod.getLength()); offlowMod.writeTo(bb); packet.setData(OFMessage.getData(sw, msg, cntx)); break; default: packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), (short)0)); String strData = "Unknown packet"; packet.setData(strData.getBytes()); break; } try { if (transport == null || !transport.isOpen() || packetClient == null) { if (!connectToPSServer()) { // No need to sendPacket if can't make connection to // the server return; } } if (sync) { log.debug("Send packet sync: {}", packet.toString()); packetClient.pushMessageSync(sendMsg); } else { log.debug("Send packet sync: ", packet.toString()); packetClient.pushMessageAsync(sendMsg); } } catch (Exception e) { log.error("Error while sending packet", e); disconnectFromPSServer(); connectToPSServer(); } } // IFloodlightModule methods @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IOFMessageFilterManagerService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(IOFMessageFilterManagerService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IThreadPoolService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); this.threadPool = context.getServiceImpl(IThreadPoolService.class); } @Override public void startUp(FloodlightModuleContext context) { // This is our 'constructor' filterMap = new ConcurrentHashMap>(); filterTimeoutMap = new ConcurrentHashMap(); serverPort = Integer.parseInt(System.getProperty("net.floodlightcontroller." + "packetstreamer.port", "9090")); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addOFMessageListener(OFType.PACKET_OUT, this); floodlightProvider.addOFMessageListener(OFType.FLOW_MOD, this); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/FloodlightContextStore.java0000664000175000017500000000215212041336206032177 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; public class FloodlightContextStore { @SuppressWarnings("unchecked") public V get(FloodlightContext bc, String key) { return (V)bc.storage.get(key); } public void put(FloodlightContext bc, String key, V value) { bc.storage.put(key, value); } public void remove(FloodlightContext bc, String key) { bc.storage.remove(key); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/0000775000175000017500000000000012041336206026144 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java0000664000175000017500000000771212041336206033102 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Returns list of modules loaded by Floodlight. * @author Rob Sherwood */ public class ModuleLoaderResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(ModuleLoaderResource.class); /** * Retrieves information about loaded modules. * @return Information about loaded modules. */ @Get("json") public Map retrieve() { return retrieveInternal(false); } /** * Retrieves all modules and their dependencies available * to Floodlight. * @param loadedOnly Whether to return all modules available or only the ones loaded. * @return Information about modules available or loaded. */ public Map retrieveInternal(boolean loadedOnly) { Map model = new HashMap(); Set loadedModules = new HashSet(); for (Object val : getContext().getAttributes().values()) { if ((val instanceof IFloodlightModule) || (val instanceof IFloodlightService)) { String serviceImpl = val.getClass().getCanonicalName(); loadedModules.add(serviceImpl); // log.debug("Tracking serviceImpl " + serviceImpl); } } for (String moduleName : FloodlightModuleLoader.moduleNameMap.keySet() ) { Map moduleInfo = new HashMap(); IFloodlightModule module = FloodlightModuleLoader.moduleNameMap.get( moduleName); Collection> deps = module.getModuleDependencies(); if ( deps == null) deps = new HashSet>(); Map depsMap = new HashMap (); for (Class service : deps) { Object serviceImpl = getContext().getAttributes().get(service.getCanonicalName()); if (serviceImpl != null) depsMap.put(service.getCanonicalName(), serviceImpl.getClass().getCanonicalName()); else depsMap.put(service.getCanonicalName(), ""); } moduleInfo.put("depends", depsMap); Collection> provides = module.getModuleServices(); if ( provides == null) provides = new HashSet>(); Map providesMap = new HashMap(); for (Class service : provides) { providesMap.put(service.getCanonicalName(), module.getServiceImpls().get(service).getClass().getCanonicalName()); } moduleInfo.put("provides", providesMap); moduleInfo.put("loaded", false); // not loaded, by default // check if this module is loaded directly if (loadedModules.contains(module.getClass().getCanonicalName())) { moduleInfo.put("loaded", true); } else { // if not, then maybe one of the services it exports is loaded for (Class service : provides) { String modString = module.getServiceImpls().get(service).getClass().getCanonicalName(); if (loadedModules.contains(modString)) moduleInfo.put("loaded", true); /* else log.debug("ServiceImpl not loaded " + modString); */ } } if ((Boolean)moduleInfo.get("loaded")|| !loadedOnly ) model.put(moduleName, moduleInfo); } return model; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java0000664000175000017500000004605012041336206033404 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Queue; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Finds all Floodlight modules in the class path and loads/starts them. * @author alexreimers * */ public class FloodlightModuleLoader { protected static Logger logger = LoggerFactory.getLogger(FloodlightModuleLoader.class); protected static Map, Collection> serviceMap; protected static Map>> moduleServiceMap; protected static Map moduleNameMap; protected static Object lock = new Object(); protected FloodlightModuleContext floodlightModuleContext; public static final String COMPILED_CONF_FILE = "floodlightdefault.properties"; public static final String FLOODLIGHT_MODULES_KEY = "floodlight.modules"; public FloodlightModuleLoader() { floodlightModuleContext = new FloodlightModuleContext(); } /** * Finds all IFloodlightModule(s) in the classpath. It creates 3 Maps. * serviceMap -> Maps a service to a module * moduleServiceMap -> Maps a module to all the services it provides * moduleNameMap -> Maps the string name to the module * @throws FloodlightModuleException If two modules are specified in the configuration * that provide the same service. */ protected static void findAllModules(Collection mList) throws FloodlightModuleException { synchronized (lock) { if (serviceMap != null) return; serviceMap = new HashMap, Collection>(); moduleServiceMap = new HashMap>>(); moduleNameMap = new HashMap(); // Get all the current modules in the classpath ClassLoader cl = Thread.currentThread().getContextClassLoader(); ServiceLoader moduleLoader = ServiceLoader.load(IFloodlightModule.class, cl); // Iterate for each module, iterate through and add it's services Iterator moduleIter = moduleLoader.iterator(); while (moduleIter.hasNext()) { IFloodlightModule m = null; try { m = moduleIter.next(); } catch (ServiceConfigurationError sce) { logger.debug("Could not find module"); //moduleIter.remove(); continue; } //} //for (IFloodlightModule m : moduleLoader) { if (logger.isDebugEnabled()) { logger.debug("Found module " + m.getClass().getName()); } // Set up moduleNameMap moduleNameMap.put(m.getClass().getCanonicalName(), m); // Set up serviceMap Collection> servs = m.getModuleServices(); if (servs != null) { moduleServiceMap.put(m, servs); for (Class s : servs) { Collection mods = serviceMap.get(s); if (mods == null) { mods = new ArrayList(); serviceMap.put(s, mods); } mods.add(m); // Make sure they haven't specified duplicate modules in the config int dupInConf = 0; for (IFloodlightModule cMod : mods) { if (mList.contains(cMod.getClass().getCanonicalName())) dupInConf += 1; } if (dupInConf > 1) { String duplicateMods = ""; for (IFloodlightModule mod : mods) { duplicateMods += mod.getClass().getCanonicalName() + ", "; } throw new FloodlightModuleException("ERROR! The configuraiton" + " file specifies more than one module that provides the service " + s.getCanonicalName() +". Please specify only ONE of the " + "following modules in the config file: " + duplicateMods); } } } } } } /** * Loads the modules from a specified configuration file. * @param fName The configuration file path * @return An IFloodlightModuleContext with all the modules to be started * @throws FloodlightModuleException */ @LogMessageDocs({ @LogMessageDoc(level="INFO", message="Loading modules from file {file name}", explanation="The controller is initializing its module " + "configuration from the specified properties file"), @LogMessageDoc(level="INFO", message="Loading default modules", explanation="The controller is initializing its module " + "configuration to the default configuration"), @LogMessageDoc(level="ERROR", message="Could not load module configuration file", explanation="The controller failed to read the " + "module configuration file", recommendation="Verify that the module configuration is " + "present. " + LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Could not load default modules", explanation="The controller failed to read the default " + "module configuration", recommendation=LogMessageDoc.CHECK_CONTROLLER) }) public IFloodlightModuleContext loadModulesFromConfig(String fName) throws FloodlightModuleException { Properties prop = new Properties(); File f = new File(fName); if (f.isFile()) { logger.info("Loading modules from file {}", fName); try { prop.load(new FileInputStream(fName)); } catch (Exception e) { logger.error("Could not load module configuration file", e); System.exit(1); } } else { logger.info("Loading default modules"); InputStream is = this.getClass().getClassLoader(). getResourceAsStream(COMPILED_CONF_FILE); try { prop.load(is); } catch (IOException e) { logger.error("Could not load default modules", e); System.exit(1); } } String moduleList = prop.getProperty(FLOODLIGHT_MODULES_KEY) .replaceAll("\\s", ""); Collection configMods = new ArrayList(); configMods.addAll(Arrays.asList(moduleList.split(","))); return loadModulesFromList(configMods, prop); } /** * Loads modules (and their dependencies) specified in the list * @param mList The array of fully qualified module names * @param ignoreList The list of Floodlight services NOT to * load modules for. Used for unit testing. * @return The ModuleContext containing all the loaded modules * @throws FloodlightModuleException */ protected IFloodlightModuleContext loadModulesFromList(Collection configMods, Properties prop, Collection ignoreList) throws FloodlightModuleException { logger.debug("Starting module loader"); if (logger.isDebugEnabled() && ignoreList != null) logger.debug("Not loading module services " + ignoreList.toString()); findAllModules(configMods); Collection moduleSet = new ArrayList(); Map, IFloodlightModule> moduleMap = new HashMap, IFloodlightModule>(); Queue moduleQ = new LinkedList(); // Add the explicitly configured modules to the q moduleQ.addAll(configMods); Set modsVisited = new HashSet(); while (!moduleQ.isEmpty()) { String moduleName = moduleQ.remove(); if (modsVisited.contains(moduleName)) continue; modsVisited.add(moduleName); IFloodlightModule module = moduleNameMap.get(moduleName); if (module == null) { throw new FloodlightModuleException("Module " + moduleName + " not found"); } // If the module provies a service that is in the // services ignorelist don't load it. if ((ignoreList != null) && (module.getModuleServices() != null)) { for (IFloodlightService ifs : ignoreList) { for (Class intsIgnore : ifs.getClass().getInterfaces()) { //System.out.println(intsIgnore.getName()); // Check that the interface extends IFloodlightService //if (intsIgnore.isAssignableFrom(IFloodlightService.class)) { //System.out.println(module.getClass().getName()); if (intsIgnore.isAssignableFrom(module.getClass())) { // We now ignore loading this module. logger.debug("Not loading module " + module.getClass().getCanonicalName() + " because interface " + intsIgnore.getCanonicalName() + " is in the ignore list."); continue; } //} } } } // Add the module to be loaded addModule(moduleMap, moduleSet, module); // Add it's dep's to the queue Collection> deps = module.getModuleDependencies(); if (deps != null) { for (Class c : deps) { IFloodlightModule m = moduleMap.get(c); if (m == null) { Collection mods = serviceMap.get(c); // Make sure only one module is loaded if ((mods == null) || (mods.size() == 0)) { throw new FloodlightModuleException("ERROR! Could not " + "find an IFloodlightModule that provides service " + c.toString()); } else if (mods.size() == 1) { IFloodlightModule mod = mods.iterator().next(); if (!modsVisited.contains(mod.getClass().getCanonicalName())) moduleQ.add(mod.getClass().getCanonicalName()); } else { boolean found = false; for (IFloodlightModule moduleDep : mods) { if (configMods.contains(moduleDep.getClass().getCanonicalName())) { // Module will be loaded, we can continue found = true; break; } } if (!found) { String duplicateMods = ""; for (IFloodlightModule mod : mods) { duplicateMods += mod.getClass().getCanonicalName() + ", "; } throw new FloodlightModuleException("ERROR! Found more " + "than one (" + mods.size() + ") IFloodlightModules that provides " + "service " + c.toString() + ". Please specify one of the following modules in the config: " + duplicateMods); } } } } } } floodlightModuleContext.setModuleSet(moduleSet); parseConfigParameters(prop); initModules(moduleSet); startupModules(moduleSet); return floodlightModuleContext; } /** * Loads modules (and their dependencies) specified in the list. * @param configMods The collection of fully qualified module names to load. * @param prop The list of properties that are configuration options. * @return The ModuleContext containing all the loaded modules. * @throws FloodlightModuleException */ public IFloodlightModuleContext loadModulesFromList(Collection configMods, Properties prop) throws FloodlightModuleException { return loadModulesFromList(configMods, prop, null); } /** * Add a module to the set of modules to load and register its services * @param moduleMap the module map * @param moduleSet the module set * @param module the module to add */ protected void addModule(Map, IFloodlightModule> moduleMap, Collection moduleSet, IFloodlightModule module) { if (!moduleSet.contains(module)) { Collection> servs = moduleServiceMap.get(module); if (servs != null) { for (Class c : servs) moduleMap.put(c, module); } moduleSet.add(module); } } /** * Allocate service implementations and then init all the modules * @param moduleSet The set of modules to call their init function on * @throws FloodlightModuleException If a module can not properly be loaded */ protected void initModules(Collection moduleSet) throws FloodlightModuleException { for (IFloodlightModule module : moduleSet) { // Get the module's service instance(s) Map, IFloodlightService> simpls = module.getServiceImpls(); // add its services to the context if (simpls != null) { for (Entry, IFloodlightService> s : simpls.entrySet()) { if (logger.isDebugEnabled()) { logger.debug("Setting " + s.getValue() + " as provider for " + s.getKey().getCanonicalName()); } if (floodlightModuleContext.getServiceImpl(s.getKey()) == null) { floodlightModuleContext.addService(s.getKey(), s.getValue()); } else { throw new FloodlightModuleException("Cannot set " + s.getValue() + " as the provider for " + s.getKey().getCanonicalName() + " because " + floodlightModuleContext.getServiceImpl(s.getKey()) + " already provides it"); } } } } for (IFloodlightModule module : moduleSet) { // init the module if (logger.isDebugEnabled()) { logger.debug("Initializing " + module.getClass().getCanonicalName()); } module.init(floodlightModuleContext); } } /** * Call each loaded module's startup method * @param moduleSet the module set to start up */ protected void startupModules(Collection moduleSet) { for (IFloodlightModule m : moduleSet) { if (logger.isDebugEnabled()) { logger.debug("Starting " + m.getClass().getCanonicalName()); } m.startUp(floodlightModuleContext); } } /** * Parses configuration parameters for each module * @param prop The properties file to use */ @LogMessageDoc(level="WARN", message="Module {module} not found or loaded. " + "Not adding configuration option {key} = {value}", explanation="Ignoring a configuration parameter for a " + "module that is not loaded.") protected void parseConfigParameters(Properties prop) { if (prop == null) return; Enumeration e = prop.propertyNames(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); // Ignore module list key if (key.equals(FLOODLIGHT_MODULES_KEY)) { continue; } String configValue = null; int lastPeriod = key.lastIndexOf("."); String moduleName = key.substring(0, lastPeriod); String configKey = key.substring(lastPeriod + 1); // Check to see if it's overridden on the command line String systemKey = System.getProperty(key); if (systemKey != null) { configValue = systemKey; } else { configValue = prop.getProperty(key); } IFloodlightModule mod = moduleNameMap.get(moduleName); if (mod == null) { logger.warn("Module {} not found or loaded. " + "Not adding configuration option {} = {}", new Object[]{moduleName, configKey, configValue}); } else { floodlightModuleContext.addConfigParam(mod, configKey, configValue); } } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java0000664000175000017500000000223412041336206033727 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.util.Collection; import java.util.Map; public interface IFloodlightModuleContext { /** * Retrieves a casted version of a module from the registry. * @param name The IFloodlightService object type * @return The IFloodlightService * @throws FloodlightModuleException If the module was not found * or a ClassCastException was encountered. */ public T getServiceImpl(Class service); /** * Returns all loaded services * @return A collection of service classes that have been loaded */ public Collection> getAllServices(); /** * Returns all loaded modules * @return All Floodlight modules that are going to be loaded */ public Collection getAllModules(); /** * Gets module specific configuration parameters. * @param module The module to get the configuration parameters for * @return A key, value map of the configuration options */ public Map getConfigParams(IFloodlightModule module); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/IFloodlightService.java0000664000175000017500000000043712041336206032540 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; /** * This is the base interface for any IFloodlightModule package that provides * a service. * @author alexreimers * */ public abstract interface IFloodlightService { // This space is intentionally left blank....don't touch it } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java0000664000175000017500000000453712041336206032372 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.util.Collection; import java.util.Map; /** * Defines an interface for loadable Floodlight modules. * * At a high level, these functions are called in the following order: *
    *
  1. getServices() : what services does this module provide *
  2. getDependencies() : list the dependencies *
  3. init() : internal initializations (don't touch other modules) *
  4. startUp() : external initializations (do touch other modules) *
* * @author alexreimers */ public interface IFloodlightModule { /** * Return the list of interfaces that this module implements. * All interfaces must inherit IFloodlightService * @return */ public Collection> getModuleServices(); /** * Instantiate (as needed) and return objects that implement each * of the services exported by this module. The map returned maps * the implemented service to the object. The object could be the * same object or different objects for different exported services. * @return The map from service interface class to service implementation */ public Map, IFloodlightService> getServiceImpls(); /** * Get a list of Modules that this module depends on. The module system * will ensure that each these dependencies is resolved before the * subsequent calls to init(). * @return The Collection of IFloodlightServices that this module depends * on. */ public Collection> getModuleDependencies(); /** * This is a hook for each module to do its internal initialization, * e.g., call setService(context.getService("Service")) * * All module dependencies are resolved when this is called, but not every module * is initialized. * * @param context * @throws FloodlightModuleException */ void init(FloodlightModuleContext context) throws FloodlightModuleException; /** * This is a hook for each module to do its external initializations, * e.g., register for callbacks or query for state in other modules * * It is expected that this function will not block and that modules that want * non-event driven CPU will spawn their own threads. * * @param context */ void startUp(FloodlightModuleContext context); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java0000664000175000017500000000034412041336206034130 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; public class FloodlightModuleException extends Exception { private static final long serialVersionUID = 1L; public FloodlightModuleException(String error) { super(error); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java0000664000175000017500000000670412041336206033624 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * The service registry for an IFloodlightProvider. * @author alexreimers */ public class FloodlightModuleContext implements IFloodlightModuleContext { protected Map, IFloodlightService> serviceMap; protected Map, Map> configParams; protected Collection moduleSet; /** * Creates the ModuleContext for use with this IFloodlightProvider. * This will be used as a module registry for all IFloodlightModule(s). */ public FloodlightModuleContext() { serviceMap = new HashMap, IFloodlightService>(); configParams = new HashMap, Map>(); } /** * Adds a IFloodlightModule for this Context. * @param clazz the service class * @param service The IFloodlightService to add to the registry */ public void addService(Class clazz, IFloodlightService service) { serviceMap.put(clazz, service); } @SuppressWarnings("unchecked") @Override public T getServiceImpl(Class service) { IFloodlightService s = serviceMap.get(service); return (T)s; } @Override public Collection> getAllServices() { return serviceMap.keySet(); } @Override public Collection getAllModules() { return moduleSet; } public void setModuleSet(Collection modSet) { this.moduleSet = modSet; } /** * Gets the configuration parameter map for a module * @param module The module to get the configuration map for, usually yourself * @return A map containing all the configuration parameters for the module, may be empty */ @Override public Map getConfigParams(IFloodlightModule module) { Map retMap = configParams.get(module.getClass()); if (retMap == null) { // Return an empty map if none exists so the module does not // need to null check the map retMap = new HashMap(); configParams.put(module.getClass(), retMap); } // also add any configuration parameters for superclasses, but // only if more specific configuration does not override it for (Class c : configParams.keySet()) { if (c.isInstance(module)) { for (Map.Entry ent : configParams.get(c).entrySet()) { if (!retMap.containsKey(ent.getKey())) { retMap.put(ent.getKey(), ent.getValue()); } } } } return retMap; } /** * Adds a configuration parameter for a module * @param mod The fully qualified module name to add the parameter to * @param key The configuration parameter key * @param value The configuration parameter value */ public void addConfigParam(IFloodlightModule mod, String key, String value) { Map moduleParams = configParams.get(mod.getClass()); if (moduleParams == null) { moduleParams = new HashMap(); configParams.put(mod.getClass(), moduleParams); } moduleParams.put(key, value); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/annotations/0000775000175000017500000000000012041336206027214 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/annotations/LogMessageCategory.java0000664000175000017500000000215312041336206033604 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Target; /** * Annotation used to set the category for log messages for a class * @author readams */ @Target({ElementType.TYPE, ElementType.METHOD}) public @interface LogMessageCategory { /** * The category for the log messages for this class * @return */ String value() default "Core"; } floodlight-0.90/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDocs.java0000664000175000017500000000236112041336206032720 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Target; /** * Annotation used to document log messages. This can be used to generate * documentation on syslog output. This version allows multiple log messages * to be documentated on an interface. * @author readams */ @Target({ElementType.TYPE, ElementType.METHOD}) public @interface LogMessageDocs { /** * A list of {@link LogMessageDoc} elements * @return the list of log message doc */ LogMessageDoc[] value(); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDoc.java0000664000175000017500000000533412041336206032540 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Target; /** * Annotation used to document log messages. This can be used to generate * documentation on syslog output. * @author readams */ @Target({ElementType.TYPE, ElementType.METHOD}) public @interface LogMessageDoc { public static final String NO_ACTION = "No action is required."; public static final String UNKNOWN_ERROR = "An unknown error occured"; public static final String GENERIC_ACTION = "Examine the returned error or exception and take " + "appropriate action."; public static final String CHECK_SWITCH = "Check the health of the indicated switch. " + "Test and troubleshoot IP connectivity."; public static final String CHECK_CONTROLLER = "Verify controller system health, CPU usage, and memory. " + "Rebooting the controller node may help if the controller " + "node is in a distressed state."; public static final String REPORT_CONTROLLER_BUG = "This is likely a defect in the controller. Please report this " + "issue. Restarting the controller or switch may help to " + "alleviate."; public static final String REPORT_SWITCH_BUG = "This is likely a defect in the switch. Please report this " + "issue. Restarting the controller or switch may help to " + "alleviate."; /** * The log level for the log message * @return the log level as a tring */ String level() default "INFO"; /** * The message that will be printed * @return the message */ String message() default UNKNOWN_ERROR; /** * An explanation of the meaning of the log message * @return the explanation */ String explanation() default UNKNOWN_ERROR; /** * The recommendated action associated with the log message * @return the recommendation */ String recommendation() default NO_ACTION; } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java0000664000175000017500000001473312041336206032772 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.packet.Ethernet; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import org.openflow.protocol.factory.BasicFactory; /** * The interface exposed by the core bundle that allows you to interact * with connected switches. * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IFloodlightProviderService extends IFloodlightService { /** * A value stored in the floodlight context containing a parsed packet * representation of the payload of a packet-in message. */ public static final String CONTEXT_PI_PAYLOAD = "net.floodlightcontroller.core.IFloodlightProvider.piPayload"; /** * The role of the controller as used by the OF 1.2 and OVS failover and * load-balancing mechanism. */ public static enum Role { EQUAL, MASTER, SLAVE }; /** * A FloodlightContextStore object that can be used to retrieve the * packet-in payload */ public static final FloodlightContextStore bcStore = new FloodlightContextStore(); /** * Adds an OpenFlow message listener * @param type The OFType the component wants to listen for * @param listener The component that wants to listen for the message */ public void addOFMessageListener(OFType type, IOFMessageListener listener); /** * Removes an OpenFlow message listener * @param type The OFType the component no long wants to listen for * @param listener The component that no longer wants to receive the message */ public void removeOFMessageListener(OFType type, IOFMessageListener listener); /** * Return a non-modifiable list of all current listeners * @return listeners */ public Map> getListeners(); /** * Returns an unmodifiable map of all actively connected OpenFlow switches. This doesn't * contain switches that are connected but the controller's in the slave role. * @return the set of actively connected switches */ public Map getSwitches(); /** * Get the current role of the controller */ public Role getRole(); /** * Get the current mapping of controller IDs to their IP addresses * Returns a copy of the current mapping. * @see IHAListener */ public Map getControllerNodeIPs(); /** * Gets the ID of the controller */ public String getControllerId(); /** * Set the role of the controller */ public void setRole(Role role); /** * Add a switch listener * @param listener The module that wants to listen for events */ public void addOFSwitchListener(IOFSwitchListener listener); /** * Remove a switch listener * @param listener The The module that no longer wants to listen for events */ public void removeOFSwitchListener(IOFSwitchListener listener); /** * Adds a listener for HA role events * @param listener The module that wants to listen for events */ public void addHAListener(IHAListener listener); /** * Removes a listener for HA role events * @param listener The module that no longer wants to listen for events */ public void removeHAListener(IHAListener listener); /** * Terminate the process */ public void terminate(); /** * Re-injects an OFMessage back into the packet processing chain * @param sw The switch to use for the message * @param msg the message to inject * @return True if successfully re-injected, false otherwise */ public boolean injectOfMessage(IOFSwitch sw, OFMessage msg); /** * Re-injects an OFMessage back into the packet processing chain * @param sw The switch to use for the message * @param msg the message to inject * @param bContext a floodlight context to use if required * @return True if successfully re-injected, false otherwise */ public boolean injectOfMessage(IOFSwitch sw, OFMessage msg, FloodlightContext bContext); /** * Process written messages through the message listeners for the controller * @param sw The switch being written to * @param m the message * @param bc any accompanying context object */ public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc); /** * Gets the BasicFactory * @return an OpenFlow message factory */ public BasicFactory getOFMessageFactory(); /** * Run the main I/O loop of the Controller. */ public void run(); /** * Add an info provider of a particular type * @param type * @param provider */ public void addInfoProvider(String type, IInfoProvider provider); /** * Remove an info provider of a particular type * @param type * @param provider */ public void removeInfoProvider(String type, IInfoProvider provider); /** * Return information of a particular type (for rest services) * @param type * @return */ public Map getControllerInfo(String type); /** * Return the controller start time in milliseconds * @return */ public long getSystemStartTime(); /** * Configure controller to always clear the flow table on the switch, * when it connects to controller. This will be true for first time switch * reconnect, as well as a switch re-attaching to Controller after HA * switch over to ACTIVE role */ public void setAlwaysClearFlowsOnSwAdd(boolean value); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java0000664000175000017500000000267512041336206031041 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; /** * * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IOFSwitchListener { /** * Fired when a switch is connected to the controller, and has sent * a features reply. * @param sw */ public void addedSwitch(IOFSwitch sw); /** * Fired when a switch is disconnected from the controller. * @param sw */ public void removedSwitch(IOFSwitch sw); /** * Fired when ports on a switch change (any change to the collection * of OFPhysicalPorts and/or to a particular port) */ public void switchPortChanged(Long switchId); /** * The name assigned to this listener * @return */ public String getName(); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/types/0000775000175000017500000000000012041336206026023 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java0000664000175000017500000000224612041336206032254 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.types; import org.openflow.protocol.OFMessage; import net.floodlightcontroller.core.IOFSwitch; public class SwitchMessagePair { private final IOFSwitch sw; private final OFMessage msg; public SwitchMessagePair(IOFSwitch sw, OFMessage msg) { this.sw = sw; this.msg = msg; } public IOFSwitch getSwitch() { return this.sw; } public OFMessage getMessage() { return this.msg; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java0000664000175000017500000000246412041336206031031 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.types; public class MacVlanPair { public Long mac; public Short vlan; public MacVlanPair(Long mac, Short vlan) { this.mac = mac; this.vlan = vlan; } public long getMac() { return mac.longValue(); } public short getVlan() { return vlan.shortValue(); } public boolean equals(Object o) { return (o instanceof MacVlanPair) && (mac.equals(((MacVlanPair) o).mac)) && (vlan.equals(((MacVlanPair) o).vlan)); } public int hashCode() { return mac.hashCode() ^ vlan.hashCode(); } }floodlight-0.90/src/main/java/net/floodlightcontroller/core/IInfoProvider.java0000664000175000017500000000165612041336206030251 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import java.util.Map; /** * * * @author Shudong Zhou */ public interface IInfoProvider { /** * Called when rest API requests information of a particular type * @param type * @return */ public Map getInfo(String type); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/0000775000175000017500000000000012041336206025434 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologySwitchResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologySwitchResource.j0000664000175000017500000000245212041336206034704 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.internal.EventHistoryTopologySwitch; import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager; import net.floodlightcontroller.util.EventHistory; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; /** * @author subrata * */ public class EventHistoryTopologySwitchResource extends ServerResource { @Get("json") public EventHistory handleEvHistReq() { // Get the event history count. Last events would be returned String evHistCount = (String)getRequestAttributes().get("count"); int count = EventHistory.EV_HISTORY_DEFAULT_SIZE; try { count = Integer.parseInt(evHistCount); } catch(NumberFormatException nFE) { // Invalid input for event count - use default value } LinkDiscoveryManager topoManager = (LinkDiscoveryManager)getContext().getAttributes(). get(ILinkDiscoveryService.class.getCanonicalName()); return new EventHistory( topoManager.evHistTopologySwitch, count); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java0000664000175000017500000001524712041336206033765 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.lang.Thread.State; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.types.MacVlanPair; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.util.HexString; import org.restlet.resource.Get; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Return switch statistics information for all switches * @author readams */ public class AllSwitchStatisticsResource extends SwitchResourceBase { protected static Logger log = LoggerFactory.getLogger(AllSwitchStatisticsResource.class); @Get("json") public Map retrieve() { String statType = (String) getRequestAttributes().get("statType"); return retrieveInternal(statType); } public Map retrieveInternal(String statType) { HashMap model = new HashMap(); OFStatisticsType type = null; REQUESTTYPE rType = null; if (statType.equals("port")) { type = OFStatisticsType.PORT; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("queue")) { type = OFStatisticsType.QUEUE; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("flow")) { type = OFStatisticsType.FLOW; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("aggregate")) { type = OFStatisticsType.AGGREGATE; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("desc")) { type = OFStatisticsType.DESC; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("table")) { type = OFStatisticsType.TABLE; rType = REQUESTTYPE.OFSTATS; } else if (statType.equals("features")) { rType = REQUESTTYPE.OFFEATURES; } else { return model; } IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); Long[] switchDpids = floodlightProvider.getSwitches().keySet().toArray(new Long[0]); List activeThreads = new ArrayList(switchDpids.length); List pendingRemovalThreads = new ArrayList(); GetConcurrentStatsThread t; for (Long l : switchDpids) { t = new GetConcurrentStatsThread(l, rType, type); activeThreads.add(t); t.start(); } // Join all the threads after the timeout. Set a hard timeout // of 12 seconds for the threads to finish. If the thread has not // finished the switch has not replied yet and therefore we won't // add the switch's stats to the reply. for (int iSleepCycles = 0; iSleepCycles < 12; iSleepCycles++) { for (GetConcurrentStatsThread curThread : activeThreads) { if (curThread.getState() == State.TERMINATED) { if (rType == REQUESTTYPE.OFSTATS) { model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getStatisticsReply()); } else if (rType == REQUESTTYPE.OFFEATURES) { model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getFeaturesReply()); } pendingRemovalThreads.add(curThread); } } // remove the threads that have completed the queries to the switches for (GetConcurrentStatsThread curThread : pendingRemovalThreads) { activeThreads.remove(curThread); } // clear the list so we don't try to double remove them pendingRemovalThreads.clear(); // if we are done finish early so we don't always get the worst case if (activeThreads.isEmpty()) { break; } // sleep for 1 s here try { Thread.sleep(1000); } catch (InterruptedException e) { log.error("Interrupted while waiting for statistics", e); } } return model; } protected class GetConcurrentStatsThread extends Thread { private List switchReply; private long switchId; private OFStatisticsType statType; private REQUESTTYPE requestType; private OFFeaturesReply featuresReply; private Map switchTable; public GetConcurrentStatsThread(long switchId, REQUESTTYPE requestType, OFStatisticsType statType) { this.switchId = switchId; this.requestType = requestType; this.statType = statType; this.switchReply = null; this.featuresReply = null; this.switchTable = null; } public List getStatisticsReply() { return switchReply; } public OFFeaturesReply getFeaturesReply() { return featuresReply; } public Map getSwitchTable() { return switchTable; } public long getSwitchId() { return switchId; } public void run() { if ((requestType == REQUESTTYPE.OFSTATS) && (statType != null)) { switchReply = getSwitchStatistics(switchId, statType); } else if (requestType == REQUESTTYPE.OFFEATURES) { featuresReply = getSwitchFeaturesReply(switchId); } } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java0000664000175000017500000000461112041336206033325 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.HashMap; import java.util.Map; import org.openflow.protocol.statistics.OFStatisticsType; import org.restlet.resource.Get; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Return switch statistics information for specific switches * @author readams */ public class SwitchStatisticsResource extends SwitchResourceBase { protected static Logger log = LoggerFactory.getLogger(SwitchStatisticsResource.class); @Get("json") public Map retrieve() { HashMap result = new HashMap(); Object values = null; String switchId = (String) getRequestAttributes().get("switchId"); String statType = (String) getRequestAttributes().get("statType"); if (statType.equals("port")) { values = getSwitchStatistics(switchId, OFStatisticsType.PORT); } else if (statType.equals("queue")) { values = getSwitchStatistics(switchId, OFStatisticsType.QUEUE); } else if (statType.equals("flow")) { values = getSwitchStatistics(switchId, OFStatisticsType.FLOW); } else if (statType.equals("aggregate")) { values = getSwitchStatistics(switchId, OFStatisticsType.AGGREGATE); } else if (statType.equals("desc")) { values = getSwitchStatistics(switchId, OFStatisticsType.DESC); } else if (statType.equals("table")) { values = getSwitchStatistics(switchId, OFStatisticsType.TABLE); } else if (statType.equals("features")) { values = getSwitchFeaturesReply(switchId); } result.put(switchId, values); return result; } } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologyLinkResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologyLinkResource.jav0000664000175000017500000000314212041336206034664 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.internal.EventHistoryTopologyLink; import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager; import net.floodlightcontroller.util.EventHistory; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author subrata * */ public class EventHistoryTopologyLinkResource extends ServerResource { // TODO - Move this to the DeviceManager Rest API protected static Logger log = LoggerFactory.getLogger(EventHistoryTopologyLinkResource.class); @Get("json") public EventHistory handleEvHistReq() { // Get the event history count. Last events would be returned String evHistCount = (String)getRequestAttributes().get("count"); int count = EventHistory.EV_HISTORY_DEFAULT_SIZE; try { count = Integer.parseInt(evHistCount); } catch(NumberFormatException nFE) { // Invalid input for event count - use default value } LinkDiscoveryManager linkDiscoveryManager = (LinkDiscoveryManager)getContext().getAttributes(). get(ILinkDiscoveryService.class.getCanonicalName()); if (linkDiscoveryManager != null) { return new EventHistory( linkDiscoveryManager.evHistTopologyLink, count); } return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java0000664000175000017500000001551412041336206032051 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.Collections; import java.util.List; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageDoc; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.statistics.OFAggregateStatisticsRequest; import org.openflow.protocol.statistics.OFFlowStatisticsRequest; import org.openflow.protocol.statistics.OFPortStatisticsRequest; import org.openflow.protocol.statistics.OFQueueStatisticsRequest; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.util.HexString; import org.restlet.resource.ResourceException; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for server resources related to switches * @author readams * */ public class SwitchResourceBase extends ServerResource { protected static Logger log = LoggerFactory.getLogger(SwitchResourceBase.class); public enum REQUESTTYPE { OFSTATS, OFFEATURES } @Override protected void doInit() throws ResourceException { super.doInit(); } @LogMessageDoc(level="ERROR", message="Failure retrieving statistics from switch {switch}", explanation="An error occurred while retrieving statistics" + "from the switch", recommendation=LogMessageDoc.CHECK_SWITCH + " " + LogMessageDoc.GENERIC_ACTION) protected List getSwitchStatistics(long switchId, OFStatisticsType statType) { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); IOFSwitch sw = floodlightProvider.getSwitches().get(switchId); Future> future; List values = null; if (sw != null) { OFStatisticsRequest req = new OFStatisticsRequest(); req.setStatisticType(statType); int requestLength = req.getLengthU(); if (statType == OFStatisticsType.FLOW) { OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest(); OFMatch match = new OFMatch(); match.setWildcards(0xffffffff); specificReq.setMatch(match); specificReq.setOutPort(OFPort.OFPP_NONE.getValue()); specificReq.setTableId((byte) 0xff); req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); requestLength += specificReq.getLength(); } else if (statType == OFStatisticsType.AGGREGATE) { OFAggregateStatisticsRequest specificReq = new OFAggregateStatisticsRequest(); OFMatch match = new OFMatch(); match.setWildcards(0xffffffff); specificReq.setMatch(match); specificReq.setOutPort(OFPort.OFPP_NONE.getValue()); specificReq.setTableId((byte) 0xff); req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); requestLength += specificReq.getLength(); } else if (statType == OFStatisticsType.PORT) { OFPortStatisticsRequest specificReq = new OFPortStatisticsRequest(); specificReq.setPortNumber((short)OFPort.OFPP_NONE.getValue()); req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); requestLength += specificReq.getLength(); } else if (statType == OFStatisticsType.QUEUE) { OFQueueStatisticsRequest specificReq = new OFQueueStatisticsRequest(); specificReq.setPortNumber((short)OFPort.OFPP_ALL.getValue()); // LOOK! openflowj does not define OFPQ_ALL! pulled this from openflow.h // note that I haven't seen this work yet though... specificReq.setQueueId(0xffffffff); req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); requestLength += specificReq.getLength(); } else if (statType == OFStatisticsType.DESC || statType == OFStatisticsType.TABLE) { // pass - nothing todo besides set the type above } req.setLengthU(requestLength); try { future = sw.getStatistics(req); values = future.get(10, TimeUnit.SECONDS); } catch (Exception e) { log.error("Failure retrieving statistics from switch " + sw, e); } } return values; } protected List getSwitchStatistics(String switchId, OFStatisticsType statType) { return getSwitchStatistics(HexString.toLong(switchId), statType); } protected OFFeaturesReply getSwitchFeaturesReply(long switchId) { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); IOFSwitch sw = floodlightProvider.getSwitches().get(switchId); Future future; OFFeaturesReply featuresReply = null; if (sw != null) { try { future = sw.getFeaturesReplyFromSwitch(); featuresReply = future.get(10, TimeUnit.SECONDS); } catch (Exception e) { log.error("Failure getting features reply from switch" + sw, e); } } return featuresReply; } protected OFFeaturesReply getSwitchFeaturesReply(String switchId) { return getSwitchFeaturesReply(HexString.toLong(switchId)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/HealthCheckResource.java0000664000175000017500000000200312041336206032145 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class HealthCheckResource extends ServerResource { public static class HealthCheckInfo { protected boolean healthy; public HealthCheckInfo() { this.healthy = true; } public boolean isHealthy() { return healthy; } public void setHealthy(boolean healthy) { this.healthy = healthy; } } @Get("json") public HealthCheckInfo healthCheck() { // Currently this is the simplest possible health check -- basically // just that the controller is still running and able to respond to // REST calls. // Eventually this should be more sophisticated and do things // like monitoring internal data structures of the controller // (e.g. async storage queue length). return new HealthCheckInfo(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java0000664000175000017500000000423712041336206032762 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import org.restlet.data.Status; import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.annotations.LogMessageDoc; import org.restlet.resource.Get; import org.restlet.resource.Post; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ControllerRoleResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(ControllerRoleResource.class); @Get("json") public RoleInfo getRole() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); return new RoleInfo(floodlightProvider.getRole()); } @Post("json") @LogMessageDoc(level="WARN", message="Invalid role value specified in REST API to " + "set controller role", explanation="An HA role change request was malformed.", recommendation=LogMessageDoc.CHECK_CONTROLLER) public void setRole(RoleInfo roleInfo) { //Role role = Role.lookupRole(roleInfo.getRole()); Role role = null; try { role = Role.valueOf(roleInfo.getRole().toUpperCase()); } catch (IllegalArgumentException e) { // The role value in the REST call didn't match a valid // role name, so just leave the role as null and handle // the error below. } if (role == null) { log.warn ("Invalid role value specified in REST API to " + "set controller role"); setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid role value"); return; } IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); floodlightProvider.setRole(role); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SystemUptimeResource.java0000664000175000017500000000140312041336206032455 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import net.floodlightcontroller.core.IFloodlightProviderService; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class SystemUptimeResource extends ServerResource { public class UptimeRest { long systemUptimeMsec; public long getSystemUptimeMsec() { return systemUptimeMsec; } } @Get("json") public UptimeRest retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); UptimeRest uptime = new UptimeRest(); uptime.systemUptimeMsec = System.currentTimeMillis() - floodlightProvider.getSystemStartTime(); return (uptime); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/ControllerMemoryResource.java0000664000175000017500000000245212041336206033326 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.HashMap; import java.util.Map; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; /** * Retrieve floodlight memory state * @author readams */ public class ControllerMemoryResource extends ServerResource { @Get("json") public Map retrieve() { HashMap model = new HashMap(); Runtime runtime = Runtime.getRuntime(); model.put("total", new Long(runtime.totalMemory())); model.put("free", new Long(runtime.freeMemory())); return model; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/0000775000175000017500000000000012041336206027770 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/UShortSerializer.java0000664000175000017500000000262412041336206034115 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; /** * Serialize a short value as an unsigned short */ public class UShortSerializer extends JsonSerializer { @Override public void serialize(Short s, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { if (s == null) jGen.writeNull(); else jGen.writeNumber(s.shortValue() & 0xffff); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/IPv4Serializer.java0000664000175000017500000000263212041336206033452 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import net.floodlightcontroller.packet.IPv4; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; /** * Serialize an integer as an IPv4 Address in dotted decimal format */ public class IPv4Serializer extends JsonSerializer { @Override public void serialize(Integer i, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeString(IPv4.fromIPv4Address(i)); } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.javafloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.j0000664000175000017500000000261112041336206034420 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.util.HexString; /** * Serialize a MAC as colon-separated hexadecimal */ public class ByteArrayMACSerializer extends JsonSerializer { @Override public void serialize(byte[] mac, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeString(HexString.toHexString(mac)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java0000664000175000017500000000260312041336206033406 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.util.HexString; /** * Serialize a DPID as colon-separated hexadecimal */ public class DPIDSerializer extends JsonSerializer { @Override public void serialize(Long dpid, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeString(HexString.toHexString(dpid, 8)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java0000664000175000017500000000260112041336206033264 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.util.HexString; /** * Serialize a MAC as colon-separated hexadecimal */ public class MACSerializer extends JsonSerializer { @Override public void serialize(Long dpid, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeString(HexString.toHexString(dpid, 6)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/ControllerSummaryResource.java0000664000175000017500000000254512041336206033516 0ustar jamespagejamespage/** * Copyright 2012, Big Switch Networks, Inc. * Originally created by Shudong Zhou, Big Switch Networks * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.Map; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; /** * Get summary counters registered by all modules * @author shudongz */ public class ControllerSummaryResource extends ServerResource { @Get("json") public Map retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); return floodlightProvider.getControllerInfo("summary"); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java0000664000175000017500000000562012041336206033647 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.Collections; import java.util.Iterator; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.util.FilterIterator; import org.openflow.util.HexString; import org.restlet.data.Form; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; /** * Get a list of switches connected to the controller * @author readams */ public class ControllerSwitchesResource extends ServerResource { public static final String DPID_ERROR = "Invalid Switch DPID: must be a 64-bit quantity, expressed in " + "hex as AA:BB:CC:DD:EE:FF:00:11"; @Get("json") public Iterator retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); Long switchDPID = null; Form form = getQuery(); String dpid = form.getFirstValue("dpid", true); if (dpid != null) { try { switchDPID = HexString.toLong(dpid); } catch (Exception e) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR); return null; } } if (switchDPID != null) { IOFSwitch sw = floodlightProvider.getSwitches().get(switchDPID); if (sw != null) return Collections.singleton(sw).iterator(); return Collections.emptySet().iterator(); } final String dpidStartsWith = form.getFirstValue("dpid__startswith", true); Iterator switer = floodlightProvider.getSwitches().values().iterator(); if (dpidStartsWith != null) { return new FilterIterator(switer) { @Override protected boolean matches(IOFSwitch value) { return value.getStringId().startsWith(dpidStartsWith); } }; } return switer; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java0000664000175000017500000000661412041336206034625 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import org.openflow.util.HexString; import org.restlet.resource.Get; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.counter.CounterStore.NetworkLayer; import net.floodlightcontroller.counter.ICounterStoreService; /** * Get the counter categories for a particular switch * @author readams */ public class SwitchCounterCategoriesResource extends CounterResourceBase { @Get("json") public Map retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); HashMap model = new HashMap(); String switchID = (String) getRequestAttributes().get("switchId"); String counterName = (String) getRequestAttributes().get("counterName"); String layer = (String) getRequestAttributes().get("layer"); Long[] switchDpids; if (switchID.equalsIgnoreCase("all")) { switchDpids = floodlightProvider.getSwitches().keySet().toArray(new Long[0]); for (Long dpid : switchDpids) { switchID = HexString.toHexString(dpid); getOneSwitchCounterCategoriesJson(model, switchID, counterName, layer); } } else { getOneSwitchCounterCategoriesJson(model, switchID, counterName, layer); } return model; } protected void getOneSwitchCounterCategoriesJson(Map model, String switchID, String counterName, String layer) { String fullCounterName = ""; NetworkLayer nl = NetworkLayer.L3; try { counterName = URLDecoder.decode(counterName, "UTF-8"); layer = URLDecoder.decode(layer, "UTF-8"); fullCounterName = switchID + ICounterStoreService.TitleDelimitor + counterName; } catch (UnsupportedEncodingException e) { //Just leave counterTitle undecoded if there is an issue - fail silently } if (layer.compareToIgnoreCase("4") == 0) { nl = NetworkLayer.L4; } List categories = this.counterStore.getAllCategories(fullCounterName, nl); if (categories != null) { model.put(fullCounterName + "." + layer, categories); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java0000664000175000017500000000622312041336206032613 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import org.openflow.util.HexString; import org.restlet.resource.Get; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.counter.ICounter; import net.floodlightcontroller.counter.ICounterStoreService; /** * Get counters for a particular switch * @author readams */ public class SwitchCounterResource extends CounterResourceBase { @Get("json") public Map retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); HashMap model = new HashMap(); String switchID = (String) getRequestAttributes().get("switchId"); String counterName = (String) getRequestAttributes().get("counterName"); Long[] switchDpids; if (switchID.equalsIgnoreCase("all")) { switchDpids = floodlightProvider.getSwitches().keySet().toArray(new Long[0]); getOneSwitchCounterJson(model, ICounterStoreService.CONTROLLER_NAME, counterName); for (Long dpid : switchDpids) { switchID = HexString.toHexString(dpid); getOneSwitchCounterJson(model, switchID, counterName); } } else { getOneSwitchCounterJson(model, switchID, counterName); } return model; } protected void getOneSwitchCounterJson(Map model, String switchID, String counterName) { String fullCounterName = ""; try { counterName = URLDecoder.decode(counterName, "UTF-8"); fullCounterName = switchID + ICounterStoreService.TitleDelimitor + counterName; } catch (UnsupportedEncodingException e) { //Just leave counterTitle undecoded if there is an issue - fail silently } ICounter counter = this.counterStore.getCounter(fullCounterName); Map sample = new HashMap (); if (counter != null) { sample.put(counter.getCounterDate().toString(), counter.getCounterValue().getLong()); model.put(switchID, sample); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/RoleInfo.java0000664000175000017500000000100412041336206030007 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import net.floodlightcontroller.core.IFloodlightProviderService.Role; public class RoleInfo { protected String role; public RoleInfo() { } public RoleInfo(String role) { setRole(role); } public RoleInfo(Role role) { this.role = (role != null) ? role.name() : "DISABLED"; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/PacketTraceResource.java0000664000175000017500000000713212041336206032200 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import java.util.concurrent.ConcurrentHashMap; import org.restlet.data.Status; import org.restlet.resource.Post; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.OFMessageFilterManager; public class PacketTraceResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(PacketTraceResource.class); public static class FilterParameters { protected String sessionId = null; protected String mac = null; protected Integer period = null; protected String direction = null; protected String output = null; public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String getMac() { return mac; } public void setMac(String mac) { this.mac = mac; } public Integer getPeriod() { return period; } public void setPeriod(Integer period) { this.period = period; } public String getDirection() { return direction; } public void setDirection(String direction) { this.direction = direction; } public String getOutput() { return output; } public void setOutput(String output) { this.output = output; } public String toString() { return "SessionID: " + sessionId + "\tmac" + mac + "\tperiod" + period + "\tdirection" + direction + "\toutput" + output; } } public static class PacketTraceOutput { protected String sessionId = null; public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } } @Post("json") public PacketTraceOutput packettrace(FilterParameters fp) { ConcurrentHashMap filter = new ConcurrentHashMap (); String sid = null; PacketTraceOutput output = new PacketTraceOutput(); OFMessageFilterManager manager = (OFMessageFilterManager)getContext() .getAttributes(). get(OFMessageFilterManager.class.getCanonicalName()); if (manager == null) { sid = null; setStatus(Status.SERVER_ERROR_SERVICE_UNAVAILABLE); } if (fp.getSessionId() != null) { filter.put("sessionId", fp.getSessionId()); } if (fp.getMac() != null) { filter.put("mac", fp.getMac()); } if (fp.getDirection() != null) { filter.put("direction", fp.getDirection()); } if (filter.isEmpty()) { setStatus(Status.CLIENT_ERROR_BAD_REQUEST); } else { if (log.isDebugEnabled()) { log.debug ("Call setupFilter: sid:{} filter:{}, period:{}", new Object[] {fp.getSessionId(), filter, fp.getPeriod()*1000}); } sid = manager.setupFilter(fp.getSessionId(), filter, fp.getPeriod()*1000); output.setSessionId(sid); setStatus(Status.SUCCESS_OK); } return output; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java0000664000175000017500000000074012041336206033475 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import java.util.Map; import org.restlet.resource.Get; import net.floodlightcontroller.core.module.ModuleLoaderResource; public class LoadedModuleLoaderResource extends ModuleLoaderResource { /** * Retrieves information about all modules available * to Floodlight. * @return Information about all modules available. */ @Get("json") public Map retrieve() { return retrieveInternal(true); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/CounterResource.java0000664000175000017500000000522312041336206031430 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import net.floodlightcontroller.counter.CounterValue; import net.floodlightcontroller.counter.ICounter; import org.restlet.resource.Get; public class CounterResource extends CounterResourceBase { @Get("json") public Map retrieve() { String counterTitle = (String) getRequestAttributes().get("counterTitle"); Map model = new HashMap(); CounterValue v; if (counterTitle.equalsIgnoreCase("all")) { Map counters = this.counterStore.getAll(); if (counters != null) { Iterator> it = counters.entrySet().iterator(); while (it.hasNext()) { Entry entry = it.next(); String counterName = entry.getKey(); v = entry.getValue().getCounterValue(); if (CounterValue.CounterType.LONG == v.getType()) { model.put(counterName, v.getLong()); } else if (v.getType() == CounterValue.CounterType.DOUBLE) { model.put(counterName, v.getDouble()); } } } } else { ICounter counter = this.counterStore.getCounter(counterTitle); if (counter != null) { v = counter.getCounterValue(); } else { v = new CounterValue(CounterValue.CounterType.LONG); } if (CounterValue.CounterType.LONG == v.getType()) { model.put(counterTitle, v.getLong()); } else if (v.getType() == CounterValue.CounterType.DOUBLE) { model.put(counterTitle, v.getDouble()); } } return model; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/StorageSourceTablesResource.java0000664000175000017500000000113412041336206033726 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import java.util.Set; import net.floodlightcontroller.storage.IStorageSourceService; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class StorageSourceTablesResource extends ServerResource { @Get("json") public Set retrieve() { IStorageSourceService storageSource = (IStorageSourceService)getContext(). getAttributes().get(IStorageSourceService.class.getCanonicalName()); Set allTableNames = storageSource.getAllTableNames(); return allTableNames; } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologyClusterResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/core/web/EventHistoryTopologyClusterResource.0000664000175000017500000000313112041336206034705 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.internal.EventHistoryTopologyCluster; import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager; import net.floodlightcontroller.util.EventHistory; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author subrata * */ public class EventHistoryTopologyClusterResource extends ServerResource { // TODO - Move this to the LinkDiscovery rest API protected static Logger log = LoggerFactory.getLogger(EventHistoryTopologyClusterResource.class); @Get("json") public EventHistory handleEvHistReq() { // Get the event history count. Last events would be returned String evHistCount = (String)getRequestAttributes().get("count"); int count = EventHistory.EV_HISTORY_DEFAULT_SIZE; try { count = Integer.parseInt(evHistCount); } catch(NumberFormatException nFE) { // Invalid input for event count - use default value } LinkDiscoveryManager topoManager = (LinkDiscoveryManager)getContext().getAttributes(). get(ILinkDiscoveryService.class.getCanonicalName()); if (topoManager != null) { return new EventHistory( topoManager.evHistTopologyCluster, count); } return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java0000664000175000017500000000577512041336206031341 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import net.floodlightcontroller.core.module.ModuleLoaderResource; import net.floodlightcontroller.restserver.RestletRoutable; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; /** * Creates a router to handle all the core web URIs * @author readams */ public class CoreWebRoutable implements RestletRoutable { @Override public String basePath() { return "/wm/core"; } @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/module/all/json", ModuleLoaderResource.class); router.attach("/module/loaded/json", LoadedModuleLoaderResource.class); router.attach("/switch/{switchId}/role/json", SwitchRoleResource.class); router.attach("/switch/all/{statType}/json", AllSwitchStatisticsResource.class); router.attach("/switch/{switchId}/{statType}/json", SwitchStatisticsResource.class); router.attach("/controller/switches/json", ControllerSwitchesResource.class); router.attach("/counter/{counterTitle}/json", CounterResource.class); router.attach("/counter/{switchId}/{counterName}/json", SwitchCounterResource.class); router.attach("/counter/categories/{switchId}/{counterName}/{layer}/json", SwitchCounterCategoriesResource.class); router.attach("/memory/json", ControllerMemoryResource.class); router.attach("/packettrace/json", PacketTraceResource.class); // Get the last {count} events from the event histories router.attach("/event-history/topology-switch/{count}/json", EventHistoryTopologySwitchResource.class); router.attach("/event-history/topology-link/{count}/json", EventHistoryTopologyLinkResource.class); router.attach("/event-history/topology-cluster/{count}/json", EventHistoryTopologyClusterResource.class); router.attach("/storage/tables/json", StorageSourceTablesResource.class); router.attach("/controller/summary/json", ControllerSummaryResource.class); router.attach("/role/json", ControllerRoleResource.class); router.attach("/health/json", HealthCheckResource.class); router.attach("/system/uptime/json", SystemUptimeResource.class); return router; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java0000664000175000017500000000235712041336206032230 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.web; import net.floodlightcontroller.counter.ICounterStoreService; import org.restlet.resource.ResourceException; import org.restlet.resource.ServerResource; public class CounterResourceBase extends ServerResource { protected ICounterStoreService counterStore; @Override protected void doInit() throws ResourceException { super.doInit(); counterStore = (ICounterStoreService)getContext().getAttributes(). get(ICounterStoreService.class.getCanonicalName()); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java0000664000175000017500000000273312041336206032077 0ustar jamespagejamespagepackage net.floodlightcontroller.core.web; import java.util.HashMap; import org.openflow.util.HexString; import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import org.restlet.resource.Get; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SwitchRoleResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(SwitchRoleResource.class); @Get("json") public Object getRole() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); String switchId = (String) getRequestAttributes().get("switchId"); RoleInfo roleInfo; if (switchId.equalsIgnoreCase("all")) { HashMap model = new HashMap(); for (IOFSwitch sw: floodlightProvider.getSwitches().values()) { switchId = sw.getStringId(); roleInfo = new RoleInfo(sw.getRole()); model.put(switchId, roleInfo); } return model; } Long dpid = HexString.toLong(switchId); IOFSwitch sw = floodlightProvider.getSwitches().get(dpid); if (sw == null) return null; roleInfo = new RoleInfo(sw.getRole()); return roleInfo; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/FloodlightContext.java0000664000175000017500000000224212041336206031162 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import java.util.concurrent.ConcurrentHashMap; /** * This is a context object where floodlight listeners can register * and later retrieve context information associated with an * event * @author readams */ public class FloodlightContext { protected ConcurrentHashMap storage = new ConcurrentHashMap(); public ConcurrentHashMap getStorage() { return storage; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/IOFSwitch.java0000664000175000017500000003036412041336206027327 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core; import java.io.IOException; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import org.jboss.netty.channel.Channel; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.statistics.OFDescriptionStatistics; import org.openflow.protocol.statistics.OFStatistics; /** * * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface IOFSwitch { // Attribute keys public static final String SWITCH_DESCRIPTION_FUTURE = "DescriptionFuture"; public static final String SWITCH_DESCRIPTION_DATA = "DescriptionData"; public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole"; public static final String SWITCH_IS_CORE_SWITCH = "isCoreSwitch"; public static final String PROP_FASTWILDCARDS = "FastWildcards"; public static final String PROP_REQUIRES_L3_MATCH = "requiresL3Match"; public static final String PROP_SUPPORTS_OFPP_TABLE = "supportsOfppTable"; public static final String PROP_SUPPORTS_OFPP_FLOOD = "supportsOfppFlood"; public static final String PROP_SUPPORTS_NETMASK_TBL = "supportsNetmaskTbl"; /** * Writes to the OFMessage to the output stream. * The message will be handed to the floodlightProvider for possible filtering * and processing by message listeners * @param m * @param bc * @throws IOException */ public void write(OFMessage m, FloodlightContext bc) throws IOException; /** * Writes the list of messages to the output stream * The message will be handed to the floodlightProvider for possible filtering * and processing by message listeners. * @param msglist * @param bc * @throws IOException */ public void write(List msglist, FloodlightContext bc) throws IOException; /** * * @throws IOException */ public void disconnectOutputStream(); /** * FIXME: remove getChannel(). All access to the channel should be through * wrapper functions in IOFSwitch * @return */ public Channel getChannel(); /** * Returns switch features from features Reply * @return */ public int getBuffers(); public int getActions(); public int getCapabilities(); public byte getTables(); /** * Set the OFFeaturesReply message returned by the switch during initial * handshake. * @param featuresReply */ public void setFeaturesReply(OFFeaturesReply featuresReply); /** * Set the SwitchProperties based on it's description * @param description */ public void setSwitchProperties(OFDescriptionStatistics description); /** * Get list of all enabled ports. This will typically be different from * the list of ports in the OFFeaturesReply, since that one is a static * snapshot of the ports at the time the switch connected to the controller * whereas this port list also reflects the port status messages that have * been received. * @return Unmodifiable list of ports not backed by the underlying collection */ public Collection getEnabledPorts(); /** * Get list of the port numbers of all enabled ports. This will typically * be different from the list of ports in the OFFeaturesReply, since that * one is a static snapshot of the ports at the time the switch connected * to the controller whereas this port list also reflects the port status * messages that have been received. * @return Unmodifiable list of ports not backed by the underlying collection */ public Collection getEnabledPortNumbers(); /** * Retrieve the port object by the port number. The port object * is the one that reflects the port status updates that have been * received, not the one from the features reply. * @param portNumber * @return port object */ public OFPhysicalPort getPort(short portNumber); /** * Retrieve the port object by the port name. The port object * is the one that reflects the port status updates that have been * received, not the one from the features reply. * @param portName * @return port object */ public OFPhysicalPort getPort(String portName); /** * Add or modify a switch port. This is called by the core controller * code in response to a OFPortStatus message. It should not typically be * called by other floodlight applications. * @param port */ public void setPort(OFPhysicalPort port); /** * Delete a port for the switch. This is called by the core controller * code in response to a OFPortStatus message. It should not typically be * called by other floodlight applications. * @param portNumber */ public void deletePort(short portNumber); /** * Delete a port for the switch. This is called by the core controller * code in response to a OFPortStatus message. It should not typically be * called by other floodlight applications. * @param portName */ public void deletePort(String portName); /** * Get list of all ports. This will typically be different from * the list of ports in the OFFeaturesReply, since that one is a static * snapshot of the ports at the time the switch connected to the controller * whereas this port list also reflects the port status messages that have * been received. * @return Unmodifiable list of ports */ public Collection getPorts(); /** * @param portName * @return Whether a port is enabled per latest port status message * (not configured down nor link down nor in spanning tree blocking state) */ public boolean portEnabled(short portName); /** * @param portNumber * @return Whether a port is enabled per latest port status message * (not configured down nor link down nor in spanning tree blocking state) */ public boolean portEnabled(String portName); /** * @param port * @return Whether a port is enabled per latest port status message * (not configured down nor link down nor in spanning tree blocking state) */ public boolean portEnabled(OFPhysicalPort port); /** * Get the datapathId of the switch * @return */ public long getId(); /** * Get a string version of the ID for this switch * @return */ public String getStringId(); /** * Retrieves attributes of this switch * @return */ public Map getAttributes(); /** * Retrieves the date the switch connected to this controller * @return the date */ public Date getConnectedSince(); /** * Returns the next available transaction id * @return */ public int getNextTransactionId(); /** * Returns a Future object that can be used to retrieve the asynchronous * OFStatisticsReply when it is available. * * @param request statistics request * @return Future object wrapping OFStatisticsReply * @throws IOException */ public Future> getStatistics(OFStatisticsRequest request) throws IOException; /** * Returns a Future object that can be used to retrieve the asynchronous * OFStatisticsReply when it is available. * * @param request statistics request * @return Future object wrapping OFStatisticsReply * @throws IOException */ public Future getFeaturesReplyFromSwitch() throws IOException; /** * Deliver the featuresReply future reply * @param reply the reply to deliver */ void deliverOFFeaturesReply(OFMessage reply); /* * Cancel features reply with a specific transction ID * @param transactionId the transaction ID */ public void cancelFeaturesReply(int transactionId); /** * Check if the switch is still connected; * Only call while holding processMessageLock * @return whether the switch is still disconnected */ public boolean isConnected(); /** * Set whether the switch is connected * Only call while holding modifySwitchLock * @param connected whether the switch is connected */ public void setConnected(boolean connected); /** * Get the current role of the controller for the switch * @return the role of the controller */ public Role getRole(); /** * Check if the controller is an active controller for the switch. * The controller is active if its role is MASTER or EQUAL. * @return whether the controller is active */ public boolean isActive(); /** * Deliver the statistics future reply * @param reply the reply to deliver */ public void deliverStatisticsReply(OFMessage reply); /** * Cancel the statistics reply with the given transaction ID * @param transactionId the transaction ID */ public void cancelStatisticsReply(int transactionId); /** * Cancel all statistics replies */ public void cancelAllStatisticsReplies(); /** * Checks if a specific switch property exists for this switch * @param name name of property * @return value for name */ boolean hasAttribute(String name); /** * Set properties for switch specific behavior * @param name name of property * @return value for name */ Object getAttribute(String name); /** * Set properties for switch specific behavior * @param name name of property * @param value value for name */ void setAttribute(String name, Object value); /** * Set properties for switch specific behavior * @param name name of property * @return current value for name or null (if not present) */ Object removeAttribute(String name); /** * Clear all flowmods on this switch */ public void clearAllFlowMods(); /** * Update broadcast cache * @param data * @return true if there is a cache hit * false if there is no cache hit. */ public boolean updateBroadcastCache(Long entry, Short port); /** * Get the portBroadcastCacheHits * @return */ public Map getPortBroadcastHits(); /** * Send a flow statistics request to the switch. This call returns after * sending the stats. request to the switch. * @param request flow statistics request message * @param xid transaction id, must be obtained by using the getXid() API. * @param caller the caller of the API. receive() callback of this * caller would be called when the reply from the switch is received. * @return the transaction id for the message sent to the switch. The * transaction id can be used to match the response with the request. Note * that the transaction id is unique only within the scope of this switch. * @throws IOException */ public void sendStatsQuery(OFStatisticsRequest request, int xid, IOFMessageListener caller) throws IOException; /** * Flush all flows queued for this switch in the current thread. * NOTE: The contract is limited to the current thread */ public void flush(); } floodlight-0.90/src/main/java/net/floodlightcontroller/core/util/0000775000175000017500000000000012041336206025634 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java0000664000175000017500000001054712041336206032302 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.IListener; import net.floodlightcontroller.core.annotations.LogMessageDoc; /** * Maintain lists of listeners ordered by dependency. * * @author readams * */ public class ListenerDispatcher> { protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class); List listeners = null; private void visit(List newlisteners, U type, HashSet visited, List ordering, T listener) { if (!visited.contains(listener)) { visited.add(listener); for (T i : newlisteners) { if (ispre(type, i, listener)) { visit(newlisteners, type, visited, ordering, i); } } ordering.add(listener); } } private boolean ispre(U type, T l1, T l2) { return (l2.isCallbackOrderingPrereq(type, l1.getName()) || l1.isCallbackOrderingPostreq(type, l2.getName())); } /** * Add a listener to the list of listeners * @param listener */ @LogMessageDoc(level="ERROR", message="No listener dependency solution: " + "No listeners without incoming dependencies", explanation="The set of listeners installed " + "have dependencies with no solution", recommendation="Install a different set of listeners " + "or install all dependencies. This is a defect in " + "the controller installation.") public void addListener(U type, T listener) { List newlisteners = new ArrayList(); if (listeners != null) newlisteners.addAll(listeners); newlisteners.add(listener); // Find nodes without outgoing edges List terminals = new ArrayList(); for (T i : newlisteners) { boolean isterm = true; for (T j : newlisteners) { if (ispre(type, i, j)) { isterm = false; break; } } if (isterm) { terminals.add(i); } } if (terminals.size() == 0) { logger.error("No listener dependency solution: " + "No listeners without incoming dependencies"); listeners = newlisteners; return; } // visit depth-first traversing in the opposite order from // the dependencies. Note we will not generally detect cycles HashSet visited = new HashSet(); List ordering = new ArrayList(); for (T term : terminals) { visit(newlisteners, type, visited, ordering, term); } listeners = ordering; } /** * Remove the given listener * @param listener the listener to remove */ public void removeListener(T listener) { if (listeners != null) { List newlisteners = new ArrayList(); newlisteners.addAll(listeners); newlisteners.remove(listener); listeners = newlisteners; } } /** * Clear all listeners */ public void clearListeners() { listeners = new ArrayList(); } /** * Get the ordered list of listeners ordered by dependencies * @return */ public List getOrderedListeners() { return listeners; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/util/AppCookie.java0000664000175000017500000000337712041336206030363 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; /*** * FIXME Need a system for registering/binding applications to a unique ID * * @author capveg * */ public class AppCookie { static final int APP_ID_BITS = 12; static final int APP_ID_SHIFT = (64 - APP_ID_BITS); // we have bits 13-31 unused here ... that's ok! static final int USER_BITS = 32; static final int USER_SHIFT = 0; /** * Encapsulate an application ID and a user block of stuff into a cookie * * @param application An ID to identify the application * @param user Some application specific data * @return a cookie for use in OFFlowMod.setCookie() */ static public long makeCookie(int application, int user) { return ((application & ((1L << APP_ID_BITS) - 1)) << APP_ID_SHIFT) | user; } static public int extractApp(long cookie) { return (int)((cookie>> APP_ID_SHIFT) & ((1L << APP_ID_BITS) - 1)); } static public int extractUser(long cookie) { return (int)((cookie>> USER_SHIFT) & ((1L << USER_BITS) - 1)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java0000664000175000017500000001321312041336206031264 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.annotations.LogMessageDoc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This allows you to represent a task that should be queued for future execution * but where you only want the task to complete once in response to some sequence * of events. For example, if you get a change notification and want to reload state, * you only want to reload the state once, at the end, and don't want to queue * an update for every notification that might come in. * * The semantics are as follows: * * If the task hasn't begun yet, do not queue a new task * * If the task has begun, set a bit to restart it after the current task finishes */ public class SingletonTask { protected static Logger logger = LoggerFactory.getLogger(SingletonTask.class); protected static class SingletonTaskContext { protected boolean taskShouldRun = false; protected boolean taskRunning = false; protected SingletonTaskWorker waitingTask = null; } protected static class SingletonTaskWorker implements Runnable { SingletonTask parent; boolean canceled = false; long nextschedule = 0; public SingletonTaskWorker(SingletonTask parent) { super(); this.parent = parent; } @Override @LogMessageDoc(level="ERROR", message="Exception while executing task", recommendation=LogMessageDoc.GENERIC_ACTION) public void run() { synchronized (parent.context) { if (canceled || !parent.context.taskShouldRun) return; parent.context.taskRunning = true; parent.context.taskShouldRun = false; } try { parent.task.run(); } catch (Exception e) { logger.error("Exception while executing task", e); } synchronized (parent.context) { parent.context.taskRunning = false; if (parent.context.taskShouldRun) { long now = System.nanoTime(); if ((nextschedule <= 0 || (nextschedule - now) <= 0)) { parent.ses.execute(this); } else { parent.ses.schedule(this, nextschedule-now, TimeUnit.NANOSECONDS); } } } } } protected SingletonTaskContext context = new SingletonTaskContext(); protected Runnable task; protected ScheduledExecutorService ses; /** * Construct a new SingletonTask for the given runnable. The context * is used to manage the state of the task execution and can be shared * by more than one instance of the runnable. * @param context * @param Task */ public SingletonTask(ScheduledExecutorService ses, Runnable task) { super(); this.task = task; this.ses = ses; } /** * Schedule the task to run if there's not already a task scheduled * If there is such a task waiting that has not already started, it * cancel that task and reschedule it to run at the given time. If the * task is already started, it will cause the task to be rescheduled once * it completes to run after delay from the time of reschedule. * * @param delay the delay in scheduling * @param unit the timeunit of the delay */ public void reschedule(long delay, TimeUnit unit) { boolean needQueue = true; SingletonTaskWorker stw = null; synchronized (context) { if (context.taskRunning || context.taskShouldRun) { if (context.taskRunning) { // schedule to restart at the right time if (delay > 0) { long now = System.nanoTime(); long then = now + TimeUnit.NANOSECONDS.convert(delay, unit); context.waitingTask.nextschedule = then; } else { context.waitingTask.nextschedule = 0; } needQueue = false; } else { // cancel and requeue context.waitingTask.canceled = true; context.waitingTask = null; } } context.taskShouldRun = true; if (needQueue) { stw = context.waitingTask = new SingletonTaskWorker(this); } } if (needQueue) { if (delay <= 0) ses.execute(stw); else ses.schedule(stw, delay, unit); } } }floodlight-0.90/src/main/java/net/floodlightcontroller/core/util/MutableInteger.java0000664000175000017500000000273312041336206031413 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; public class MutableInteger extends Number { private static final long serialVersionUID = 1L; int mutableInt; public MutableInteger(int value) { this.mutableInt = value; } public void setValue(int value) { this.mutableInt = value; } @Override public double doubleValue() { return (double) mutableInt; } @Override public float floatValue() { // TODO Auto-generated method stub return (float) mutableInt; } @Override public int intValue() { // TODO Auto-generated method stub return mutableInt; } @Override public long longValue() { // TODO Auto-generated method stub return (long) mutableInt; } } floodlight-0.90/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java0000664000175000017500000000570512041336206031337 0ustar jamespagejamespagepackage net.floodlightcontroller.core; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.core.internal.Controller; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.threadpool.IThreadPoolService; public class FloodlightProvider implements IFloodlightModule { Controller controller; @Override public Collection> getModuleServices() { Collection> services = new ArrayList>(1); services.add(IFloodlightProviderService.class); return services; } @Override public Map, IFloodlightService> getServiceImpls() { controller = new Controller(); Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IFloodlightProviderService.class, controller); return m; } @Override public Collection> getModuleDependencies() { Collection> dependencies = new ArrayList>(4); dependencies.add(IStorageSourceService.class); dependencies.add(IPktInProcessingTimeService.class); dependencies.add(IRestApiService.class); dependencies.add(ICounterStoreService.class); dependencies.add(IThreadPoolService.class); return dependencies; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { controller.setStorageSourceService( context.getServiceImpl(IStorageSourceService.class)); controller.setPktInProcessingService( context.getServiceImpl(IPktInProcessingTimeService.class)); controller.setCounterStore( context.getServiceImpl(ICounterStoreService.class)); controller.setRestApiService( context.getServiceImpl(IRestApiService.class)); controller.setThreadPoolService( context.getServiceImpl(IThreadPoolService.class)); controller.init(context.getConfigParams(this)); } @Override public void startUp(FloodlightModuleContext context) { controller.startupComponents(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/packetstreamer/0000775000175000017500000000000012041336206026741 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/packetstreamer/PacketStreamerHandler.java0000664000175000017500000001536212041336206034023 0ustar jamespagejamespagepackage net.floodlightcontroller.packetstreamer; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.packetstreamer.thrift.*; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Map; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The PacketStreamer handler class that implements the service APIs. */ @LogMessageCategory("OpenFlow Message Tracing") public class PacketStreamerHandler implements PacketStreamer.Iface { /** * The queue wrapper class that contains the queue for the streamed packets. */ protected class SessionQueue { protected BlockingQueue pQueue; /** * The queue wrapper constructor */ public SessionQueue() { this.pQueue = new LinkedBlockingQueue(); } /** * The access method to get to the internal queue. */ public BlockingQueue getQueue() { return this.pQueue; } } /** * The class logger object */ protected static Logger log = LoggerFactory.getLogger(PacketStreamerServer.class); /** * A sessionId-to-queue mapping */ protected Map msgQueues; /** * The handler's constructor */ public PacketStreamerHandler() { this.msgQueues = new ConcurrentHashMap(); } /** * The implementation for getPackets() function. * This is a blocking API. * * @param sessionid * @return A list of packets associated with the session */ @Override @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Interrupted while waiting for session start", explanation="The thread was interrupted waiting " + "for the packet streamer session to start", recommendation=LogMessageDoc.CHECK_CONTROLLER), @LogMessageDoc(level="ERROR", message="Interrupted while waiting for packets", explanation="The thread was interrupted waiting " + "for packets", recommendation=LogMessageDoc.CHECK_CONTROLLER) }) public List getPackets(String sessionid) throws org.apache.thrift.TException { List packets = new ArrayList(); int count = 0; while (!msgQueues.containsKey(sessionid) && count++ < 100) { log.debug("Queue for session {} doesn't exist yet.", sessionid); try { Thread.sleep(100); // Wait 100 ms to check again. } catch (InterruptedException e) { log.error("Interrupted while waiting for session start"); } } if (count < 100) { SessionQueue pQueue = msgQueues.get(sessionid); BlockingQueue queue = pQueue.getQueue(); // Block if queue is empty try { packets.add(queue.take()); queue.drainTo(packets); } catch (InterruptedException e) { log.error("Interrupted while waiting for packets"); } } return packets; } /** * The implementation for pushMessageSync() function. * * @param msg * @return 1 for success, 0 for failure * @throws TException */ @Override @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="Could not push empty message", explanation="An empty message was sent to the packet streamer", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG), @LogMessageDoc(level="ERROR", message="queue for session {sessionId} is null", explanation="The queue for the packet streamer session " + "is missing", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) }) public int pushMessageSync(Message msg) throws org.apache.thrift.TException { if (msg == null) { log.error("Could not push empty message"); return 0; } List sessionids = msg.getSessionIDs(); for (String sid : sessionids) { SessionQueue pQueue = null; if (!msgQueues.containsKey(sid)) { pQueue = new SessionQueue(); msgQueues.put(sid, pQueue); } else { pQueue = msgQueues.get(sid); } log.debug("pushMessageSync: SessionId: " + sid + " Receive a message, " + msg.toString() + "\n"); ByteBuffer bb = ByteBuffer.wrap(msg.getPacket().getData()); //ByteBuffer dst = ByteBuffer.wrap(msg.getPacket().toString().getBytes()); BlockingQueue queue = pQueue.getQueue(); if (queue != null) { if (!queue.offer(bb)) { log.error("Failed to queue message for session: " + sid); } else { log.debug("insert a message to session: " + sid); } } else { log.error("queue for session {} is null", sid); } } return 1; } /** * The implementation for pushMessageAsync() function. * * @param msg * @throws TException */ @Override public void pushMessageAsync(Message msg) throws org.apache.thrift.TException { pushMessageSync(msg); return; } /** * The implementation for terminateSession() function. * It removes the session to queue association. * @param sessionid * @throws TException */ @Override public void terminateSession(String sessionid) throws org.apache.thrift.TException { if (!msgQueues.containsKey(sessionid)) { return; } SessionQueue pQueue = msgQueues.get(sessionid); log.debug("terminateSession: SessionId: " + sessionid + "\n"); String data = "FilterTimeout"; ByteBuffer bb = ByteBuffer.wrap(data.getBytes()); BlockingQueue queue = pQueue.getQueue(); if (queue != null) { if (!queue.offer(bb)) { log.error("Failed to queue message for session: " + sessionid); } msgQueues.remove(sessionid); } else { log.error("queue for session {} is null", sessionid); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/packetstreamer/PacketStreamerServer.java0000664000175000017500000000471012041336206033707 0ustar jamespagejamespagepackage net.floodlightcontroller.packetstreamer; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.server.TServer; import org.apache.thrift.server.THsHaServer; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TNonblockingServerSocket; import org.apache.thrift.transport.TNonblockingServerTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.annotations.LogMessageCategory; // Generated code import net.floodlightcontroller.packetstreamer.thrift.*; /** * The PacketStreamer Server that brokers the packet streaming service. */ @LogMessageCategory("OpenFlow Message Tracing") public class PacketStreamerServer { protected static Logger log = LoggerFactory.getLogger(PacketStreamerServer.class); protected static int port = 9090; protected static PacketStreamerHandler handler; protected static PacketStreamer.Processor processor; /** * Main function entry point; * @param args */ public static void main(String [] args) { try { port = Integer.parseInt(System.getProperty("net.floodlightcontroller.packetstreamer.port", "9090")); handler = new PacketStreamerHandler(); processor = new PacketStreamer.Processor(handler); Runnable simple = new Runnable() { public void run() { hshaServer(processor); } }; new Thread(simple).start(); } catch (Exception x) { x.printStackTrace(); } } /** * The function to create a thrift Half-Sync and Half-Async Server. * @param processor */ public static void hshaServer(PacketStreamer.Processor processor) { try { TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(port); THsHaServer.Args args = new THsHaServer.Args(serverTransport); args.processor(processor); args.transportFactory(new TFramedTransport.Factory()); args.protocolFactory(new TBinaryProtocol.Factory(true, true)); TServer server = new THsHaServer(args); log.info("Starting the packetstreamer hsha server on port {} ...", port); server.serve(); } catch (Exception e) { e.printStackTrace(); } } } floodlight-0.90/src/main/java/net/floodlightcontroller/packetstreamer/PacketStreamerClient.java0000664000175000017500000000631112041336206033656 0ustar jamespagejamespagepackage net.floodlightcontroller.packetstreamer; import net.floodlightcontroller.packetstreamer.thrift.*; import java.util.List; import java.util.ArrayList; import org.apache.thrift.TException; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransportException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The PacketStreamer Sample Client. */ public class PacketStreamerClient { protected static Logger log = LoggerFactory.getLogger(PacketStreamerClient.class); /** * Main function entry point; * @param args */ public static void main(String [] args) { try { int serverPort = Integer.parseInt(System.getProperty("net.floodlightcontroller.packetstreamer.port", "9090")); TTransport transport; transport = new TFramedTransport(new TSocket("localhost", serverPort)); transport.open(); TProtocol protocol = new TBinaryProtocol(transport); PacketStreamer.Client client = new PacketStreamer.Client(protocol); sendPackets(client, (short)2, OFMessageType.PACKET_IN, true); log.debug("Terminate session1"); client.terminateSession("session1"); transport.close(); } catch (TException x) { x.printStackTrace(); } } /** * Send test packets of the given OFMessageType to the packetstreamer server; * @param client Packetstreamer client object * @param numPackets number of test packets to be sent * @param ofType OFMessageType of the test packets * @param sync true if send with synchronous interface, false for asynchronous interface * @throws TException */ private static void sendPackets(PacketStreamer.Client client, short numPackets, OFMessageType ofType, boolean sync) throws TException { while (numPackets-- > 0) { Message msg = new Message(); Packet packet = new Packet(); List sids = new ArrayList(); sids.add("session1"); sids.add("session2"); msg.setSessionIDs(sids); packet.setMessageType(ofType); long sw_dpid = numPackets/40 + 1; packet.setSwPortTuple(new SwitchPortTuple(sw_dpid, (short)(numPackets - (sw_dpid-1)*40))); String strData = "New data, sequence " + numPackets; packet.setData(strData.getBytes()); msg.setPacket(packet); try { if (sync) { client.pushMessageSync(msg); log.debug("Send packet sync: " + msg.toString()); } else { client.pushMessageAsync(msg); log.debug("Send packet sync: " + msg.toString()); } } catch (TTransportException e) { log.error(e.toString()); } try { Thread.sleep(100); } catch (Exception e) {} } } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/0000775000175000017500000000000012041336206025603 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/topology/ITopologyService.java0000664000175000017500000001602312041336206031716 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import java.util.Date; import java.util.List; import java.util.Set; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; public interface ITopologyService extends IFloodlightService { public void addListener(ITopologyListener listener); public Date getLastUpdateTime(); /** * Query to determine if devices must be learned on a given switch port. */ public boolean isAttachmentPointPort(long switchid, short port); public boolean isAttachmentPointPort(long switchid, short port, boolean tunnelEnabled); public long getOpenflowDomainId(long switchId); public long getOpenflowDomainId(long switchId, boolean tunnelEnabled); /** * Returns the identifier of the L2 domain of a given switch. * @param switchId The DPID of the switch in long form * @return The DPID of the switch that is the key for the cluster */ public long getL2DomainId(long switchId); public long getL2DomainId(long switchId, boolean tunnelEnabled); /** * Queries whether two switches are in the same cluster. * @param switch1 * @param switch2 * @return true if the switches are in the same cluster */ public boolean inSameOpenflowDomain(long switch1, long switch2); public boolean inSameOpenflowDomain(long switch1, long switch2, boolean tunnelEnabled); /** * Queries whether two switches are in the same island. * Currently, island and cluster are the same. In future, * islands could be different than clusters. * @param switch1 * @param switch2 * @return True of they are in the same island, false otherwise */ public boolean inSameL2Domain(long switch1, long switch2); public boolean inSameL2Domain(long switch1, long switch2, boolean tunnelEnabled); public boolean isBroadcastDomainPort(long sw, short port); public boolean isBroadcastDomainPort(long sw, short port, boolean tunnelEnabled); public boolean isAllowed(long sw, short portId); public boolean isAllowed(long sw, short portId, boolean tunnelEnabled); /** * Indicates if an attachment point on the new switch port is consistent * with the attachment point on the old switch port or not. */ public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort); public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort, boolean tunnelEnabled); /** * Indicates if the two switch ports are connected to the same * broadcast domain or not. * @param s1 * @param p1 * @param s2 * @param p2 * @return */ public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2); public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2, boolean tunnelEnabled); /** * Gets a list of ports on a given switch that are known to topology. * @param sw The switch DPID in long * @return The set of ports on this switch */ public Set getPortsWithLinks(long sw); public Set getPortsWithLinks(long sw, boolean tunnelEnabled); /** Get broadcast ports on a target switch for a given attachmentpoint * point port. */ public Set getBroadcastPorts(long targetSw, long src, short srcPort); public Set getBroadcastPorts(long targetSw, long src, short srcPort, boolean tunnelEnabled); /** * */ public boolean isIncomingBroadcastAllowed(long sw, short portId); public boolean isIncomingBroadcastAllowed(long sw, short portId, boolean tunnelEnabled); /** Get the proper outgoing switchport for a given pair of src-dst * switchports. */ public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort); public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled); public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort); public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled); /** * If the dst is not allowed by the higher-level topology, * this method provides the topologically equivalent broadcast port. * @param src * @param dst * @return the allowed broadcast port */ public NodePortTuple getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, short dstPort); public NodePortTuple getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled); /** * If the src broadcast domain port is not allowed for incoming * broadcast, this method provides the topologically equivalent * incoming broadcast-allowed * src port. * @param src * @param dst * @return the allowed broadcast port */ public NodePortTuple getAllowedIncomingBroadcastPort(long src, short srcPort); public NodePortTuple getAllowedIncomingBroadcastPort(long src, short srcPort, boolean tunnelEnabled); /** * Gets the set of ports that belong to a broadcast domain. * @return The set of ports that belong to a broadcast domain. */ public Set getBroadcastDomainPorts(); public Set getTunnelPorts(); /** * Returns a set of blocked ports. The set of blocked * ports is the union of all the blocked ports across all * instances. * @return */ public Set getBlockedPorts(); /** * ITopologyListener provides topologyChanged notification, * but not *what* the changes were. * This method returns the delta in the linkUpdates between the current and the previous topology instance. * @return */ public List getLastLinkUpdates(); /** * Switch methods */ public Set getPorts(long sw); } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/Cluster.java0000664000175000017500000000354412041336206030075 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.floodlightcontroller.routing.Link; import org.openflow.util.HexString; public class Cluster { protected long id; // the lowest id of the nodes protected Map> links; // set of links connected to a node. public Cluster() { id = Long.MAX_VALUE; links = new HashMap>(); } public long getId() { return id; } public void setId(long id) { this.id = id; } public Map> getLinks() { return links; } public Set getNodes() { return links.keySet(); } void add(long n) { if (links.containsKey(n) == false) { links.put(n, new HashSet()); if (n < id) id = n; } } void addLink(Link l) { if (links.containsKey(l.getSrc()) == false) { links.put(l.getSrc(), new HashSet()); if (l.getSrc() < id) id = l.getSrc(); } links.get(l.getSrc()).add(l); if (links.containsKey(l.getDst()) == false) { links.put(l.getDst(), new HashSet()); if (l.getDst() < id) id = l.getDst(); } links.get(l.getDst()).add(l); } @Override public int hashCode() { return (int) (id + id >>>32); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Cluster other = (Cluster) obj; return (this.id == other.id); } public String toString() { return "[Cluster id=" + HexString.toHexString(id) + ", " + links.keySet() + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java0000664000175000017500000000472212041336206031217 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.core.web.serializers.UShortSerializer; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; /** * A NodePortTuple is similar to a SwitchPortTuple * but it only stores IDs instead of references * to the actual objects. * @author srini */ public class NodePortTuple { protected long nodeId; // switch DPID protected short portId; // switch port id /** * Creates a NodePortTuple * @param nodeId The DPID of the switch * @param portId The port of the switch */ public NodePortTuple(long nodeId, short portId) { this.nodeId = nodeId; this.portId = portId; } public NodePortTuple(long nodeId, int portId) { this.nodeId = nodeId; this.portId = (short) portId; } @JsonProperty("switch") @JsonSerialize(using=DPIDSerializer.class) public long getNodeId() { return nodeId; } public void setNodeId(long nodeId) { this.nodeId = nodeId; } @JsonProperty("port") @JsonSerialize(using=UShortSerializer.class) public short getPortId() { return portId; } public void setPortId(short portId) { this.portId = portId; } public String toString() { return "[id=" + HexString.toHexString(nodeId) + ", port=" + new Short(portId) + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (nodeId ^ (nodeId >>> 32)); result = prime * result + portId; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; NodePortTuple other = (NodePortTuple) obj; if (nodeId != other.nodeId) return false; if (portId != other.portId) return false; return true; } /** * API to return a String value formed wtih NodeID and PortID * The portID is a 16-bit field, so mask it as an integer to get full * positive value * @return */ public String toKeyString() { return (HexString.toHexString(nodeId)+ "|" + (portId & 0xffff)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/NodePair.java0000664000175000017500000000221412041336206030146 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; public class NodePair { private long min; private long max; public NodePair(long a, long b) { if (a < b) { min = a; max = b; } else { min = b; max = a; } } public long getNode() { return min; } public long getOtherNode() { return max; } public String toString() { return "[" + new Long(min) + ", " + new Long(max) + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (max ^ (max >>> 32)); result = prime * result + (int) (min ^ (min >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; NodePair other = (NodePair) obj; if (max != other.max) return false; if (min != other.min) return false; return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/OrderedNodePair.java0000664000175000017500000000212212041336206031451 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; public class OrderedNodePair { private long src; private long dst; public OrderedNodePair(long s, long d) { src = s; dst = d; } public long getSrc() { return src; } public long getDst() { return dst; } @Override public int hashCode() { final int prime = 2417; int result = 1; result = prime * result + (int) (dst ^ (dst >>> 32)); result = prime * result + (int) (src ^ (src >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; OrderedNodePair other = (OrderedNodePair) obj; if (dst != other.dst) return false; if (src != other.src) return false; return true; } @Override public String toString() { return "OrderedNodePair [src=" + src + ", dst=" + dst + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/0000775000175000017500000000000012041336206026360 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java0000664000175000017500000000226712041336206033202 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import org.restlet.Context; import org.restlet.routing.Router; import net.floodlightcontroller.linkdiscovery.web.LinksResource; import net.floodlightcontroller.restserver.RestletRoutable; public class TopologyWebRoutable implements RestletRoutable { /** * Create the Restlet router and bind to the proper resources. */ @Override public Router getRestlet(Context context) { Router router = new Router(context); router.attach("/links/json", LinksResource.class); router.attach("/tunnellinks/json", TunnelLinksResource.class); router.attach("/switchclusters/json", SwitchClustersResource.class); router.attach("/broadcastdomainports/json", BroadcastDomainPortsResource.class); router.attach("/enabledports/json", EnabledPortsResource.class); router.attach("/blockedports/json", BlockedPortsResource.class); router.attach("/route/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", RouteResource.class); return router; } /** * Set the base path for the Topology */ @Override public String basePath() { return "/wm/topology"; } } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.javafloodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.jav0000664000175000017500000000116512041336206034657 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import java.util.Set; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class BroadcastDomainPortsResource extends ServerResource { @Get("json") public Set retrieve() { ITopologyService topology = (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); return topology.getBroadcastDomainPorts(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java0000664000175000017500000000261212041336206033316 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import java.util.ArrayList; import java.util.List; import java.util.Set; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class EnabledPortsResource extends ServerResource { @Get("json") public List retrieve() { List result = new ArrayList(); IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); ITopologyService topology= (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); if (floodlightProvider == null || topology == null) return result; Set switches = floodlightProvider.getSwitches().keySet(); if (switches == null) return result; for(long sw: switches) { Set ports = topology.getPorts(sw); if (ports == null) continue; for(short p: ports) { result.add(new NodePortTuple(sw, p)); } } return result; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java0000664000175000017500000000114512041336206033327 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import java.util.Set; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class BlockedPortsResource extends ServerResource { @Get("json") public Set retrieve() { ITopologyService topology = (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); return topology.getBlockedPorts(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java0000664000175000017500000000330112041336206032026 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import java.util.List; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.topology.NodePortTuple; import org.openflow.util.HexString; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RouteResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(RouteResource.class); @Get("json") public List retrieve() { IRoutingService routing = (IRoutingService)getContext().getAttributes(). get(IRoutingService.class.getCanonicalName()); String srcDpid = (String) getRequestAttributes().get("src-dpid"); String srcPort = (String) getRequestAttributes().get("src-port"); String dstDpid = (String) getRequestAttributes().get("dst-dpid"); String dstPort = (String) getRequestAttributes().get("dst-port"); log.debug( srcDpid + "--" + srcPort + "--" + dstDpid + "--" + dstPort); long longSrcDpid = HexString.toLong(srcDpid); short shortSrcPort = Short.parseShort(srcPort); long longDstDpid = HexString.toLong(dstDpid); short shortDstPort = Short.parseShort(dstPort); Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort); if (result!=null) { return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort).getPath(); } else { log.debug("ERROR! no route found"); return null; } } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java0000664000175000017500000000114312041336206033200 0ustar jamespagejamespagepackage net.floodlightcontroller.topology.web; import java.util.Set; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class TunnelLinksResource extends ServerResource { @Get("json") public Set retrieve() { ITopologyService topology = (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); return topology.getTunnelPorts(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java0000664000175000017500000000556012041336206033727 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.topology.web; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.topology.ITopologyService; import org.openflow.util.HexString; import org.restlet.data.Form; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; /** * Returns a JSON map of > */ public class SwitchClustersResource extends ServerResource { @Get("json") public Map> retrieve() { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); ITopologyService topology = (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); Form form = getQuery(); String queryType = form.getFirstValue("type", true); boolean openflowDomain = true; if (queryType != null && "l2".equals(queryType)) { openflowDomain = false; } Map> switchClusterMap = new HashMap>(); for (Entry entry : floodlightProvider.getSwitches().entrySet()) { Long clusterDpid = (openflowDomain ? topology.getOpenflowDomainId(entry.getValue().getId()) :topology.getL2DomainId(entry.getValue().getId())); List switchesInCluster = switchClusterMap.get(HexString.toHexString(clusterDpid)); if (switchesInCluster != null) { switchesInCluster.add(HexString.toHexString(entry.getKey())); } else { List l = new ArrayList(); l.add(HexString.toHexString(entry.getKey())); switchClusterMap.put(HexString.toHexString(clusterDpid), l); } } return switchClusterMap; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java0000664000175000017500000007122012041336206031751 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.util.ClusterDFS; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.routing.BroadcastTree; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.routing.RouteId; import net.floodlightcontroller.util.LRUHashMap; /** * A representation of a network topology. Used internally by * {@link TopologyManager} */ @LogMessageCategory("Network Topology") public class TopologyInstance { public static final short LT_SH_LINK = 1; public static final short LT_BD_LINK = 2; public static final short LT_TUNNEL = 3; public static final int MAX_LINK_WEIGHT = 10000; public static final int MAX_PATH_WEIGHT = Integer.MAX_VALUE - MAX_LINK_WEIGHT - 1; public static final int PATH_CACHE_SIZE = 1000; protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class); protected Map> switchPorts; // Set of ports for each switch /** Set of switch ports that are marked as blocked. A set of blocked * switch ports may be provided at the time of instantiation. In addition, * we may add additional ports to this set. */ protected Set blockedPorts; protected Map> switchPortLinks; // Set of links organized by node port tuple /** Set of links that are blocked. */ protected Set blockedLinks; protected Set switches; protected Set broadcastDomainPorts; protected Set tunnelPorts; protected Set clusters; // set of openflow domains protected Map switchClusterMap; // switch to OF domain map // States for routing protected Map destinationRootedTrees; protected Map> clusterBroadcastNodePorts; protected Map clusterBroadcastTrees; protected LRUHashMap pathcache; public TopologyInstance() { this.switches = new HashSet(); this.switchPorts = new HashMap>(); this.switchPortLinks = new HashMap>(); this.broadcastDomainPorts = new HashSet(); this.tunnelPorts = new HashSet(); this.blockedPorts = new HashSet(); this.blockedLinks = new HashSet(); } public TopologyInstance(Map> switchPorts, Map> switchPortLinks) { this.switches = new HashSet(switchPorts.keySet()); this.switchPorts = new HashMap>(switchPorts); this.switchPortLinks = new HashMap>(switchPortLinks); this.broadcastDomainPorts = new HashSet(); this.tunnelPorts = new HashSet(); this.blockedPorts = new HashSet(); this.blockedLinks = new HashSet(); clusters = new HashSet(); switchClusterMap = new HashMap(); } public TopologyInstance(Map> switchPorts, Set blockedPorts, Map> switchPortLinks, Set broadcastDomainPorts, Set tunnelPorts){ // copy these structures this.switches = new HashSet(switchPorts.keySet()); this.switchPorts = new HashMap>(); for(long sw: switchPorts.keySet()) { this.switchPorts.put(sw, new HashSet(switchPorts.get(sw))); } this.blockedPorts = new HashSet(blockedPorts); this.switchPortLinks = new HashMap>(); for(NodePortTuple npt: switchPortLinks.keySet()) { this.switchPortLinks.put(npt, new HashSet(switchPortLinks.get(npt))); } this.broadcastDomainPorts = new HashSet(broadcastDomainPorts); this.tunnelPorts = new HashSet(tunnelPorts); blockedLinks = new HashSet(); clusters = new HashSet(); switchClusterMap = new HashMap(); destinationRootedTrees = new HashMap(); clusterBroadcastTrees = new HashMap(); clusterBroadcastNodePorts = new HashMap>(); pathcache = new LRUHashMap(PATH_CACHE_SIZE); } public void compute() { // Step 1: Compute clusters ignoring broadcast domain links // Create nodes for clusters in the higher level topology // Must ignore blocked links. identifyOpenflowDomains(); // Step 0: Remove all links connected to blocked ports. // removeLinksOnBlockedPorts(); // Step 1.1: Add links to clusters // Avoid adding blocked links to clusters addLinksToOpenflowDomains(); // Step 2. Compute shortest path trees in each cluster for // unicast routing. The trees are rooted at the destination. // Cost for tunnel links and direct links are the same. calculateShortestPathTreeInClusters(); // Step 3. Compute broadcast tree in each cluster. // Cost for tunnel links are high to discourage use of // tunnel links. The cost is set to the number of nodes // in the cluster + 1, to use as minimum number of // clusters as possible. calculateBroadcastNodePortsInClusters(); // Step 4. print topology. // printTopology(); } public void printTopology() { log.trace("-----------------------------------------------"); log.trace("Links: {}",this.switchPortLinks); log.trace("broadcastDomainPorts: {}", broadcastDomainPorts); log.trace("tunnelPorts: {}", tunnelPorts); log.trace("clusters: {}", clusters); log.trace("destinationRootedTrees: {}", destinationRootedTrees); log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts); log.trace("-----------------------------------------------"); } protected void addLinksToOpenflowDomains() { for(long s: switches) { if (switchPorts.get(s) == null) continue; for (short p: switchPorts.get(s)) { NodePortTuple np = new NodePortTuple(s, p); if (switchPortLinks.get(np) == null) continue; if (isBroadcastDomainPort(np)) continue; for(Link l: switchPortLinks.get(np)) { if (isBlockedLink(l)) continue; if (isBroadcastDomainLink(l)) continue; Cluster c1 = switchClusterMap.get(l.getSrc()); Cluster c2 = switchClusterMap.get(l.getDst()); if (c1 ==c2) { c1.addLink(l); } } } } } /** * @author Srinivasan Ramasubramanian * * This function divides the network into clusters. Every cluster is * a strongly connected component. The network may contain unidirectional * links. The function calls dfsTraverse for performing depth first * search and cluster formation. * * The computation of strongly connected components is based on * Tarjan's algorithm. For more details, please see the Wikipedia * link below. * * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ @LogMessageDoc(level="ERROR", message="No DFS object for switch {} found.", explanation="The internal state of the topology module is corrupt", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) public void identifyOpenflowDomains() { Map dfsList = new HashMap(); if (switches == null) return; for (Long key: switches) { ClusterDFS cdfs = new ClusterDFS(); dfsList.put(key, cdfs); } Set currSet = new HashSet(); for (Long sw: switches) { ClusterDFS cdfs = dfsList.get(sw); if (cdfs == null) { log.error("No DFS object for switch {} found.", sw); }else if (!cdfs.isVisited()) { dfsTraverse(0, 1, sw, dfsList, currSet); } } } /** * @author Srinivasan Ramasubramanian * * This algorithm computes the depth first search (DFS) traversal of the * switches in the network, computes the lowpoint, and creates clusters * (of strongly connected components). * * The computation of strongly connected components is based on * Tarjan's algorithm. For more details, please see the Wikipedia * link below. * * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm * * The initialization of lowpoint and the check condition for when a * cluster should be formed is modified as we do not remove switches that * are already part of a cluster. * * A return value of -1 indicates that dfsTraverse failed somewhere in the middle * of computation. This could happen when a switch is removed during the cluster * computation procedure. * * @param parentIndex: DFS index of the parent node * @param currIndex: DFS index to be assigned to a newly visited node * @param currSw: ID of the current switch * @param dfsList: HashMap of DFS data structure for each switch * @param currSet: Set of nodes in the current cluster in formation * @return long: DSF index to be used when a new node is visited */ private long dfsTraverse (long parentIndex, long currIndex, long currSw, Map dfsList, Set currSet) { //Get the DFS object corresponding to the current switch ClusterDFS currDFS = dfsList.get(currSw); // Get all the links corresponding to this switch //Assign the DFS object with right values. currDFS.setVisited(true); currDFS.setDfsIndex(currIndex); currDFS.setParentDFSIndex(parentIndex); currIndex++; // Traverse the graph through every outgoing link. if (switchPorts.get(currSw) != null){ for(Short p: switchPorts.get(currSw)) { Set lset = switchPortLinks.get(new NodePortTuple(currSw, p)); if (lset == null) continue; for(Link l:lset) { long dstSw = l.getDst(); // ignore incoming links. if (dstSw == currSw) continue; // ignore if the destination is already added to // another cluster if (switchClusterMap.get(dstSw) != null) continue; // ignore the link if it is blocked. if (isBlockedLink(l)) continue; // ignore this link if it is in broadcast domain if (isBroadcastDomainLink(l)) continue; // Get the DFS object corresponding to the dstSw ClusterDFS dstDFS = dfsList.get(dstSw); if (dstDFS.getDfsIndex() < currDFS.getDfsIndex()) { // could be a potential lowpoint if (dstDFS.getDfsIndex() < currDFS.getLowpoint()) currDFS.setLowpoint(dstDFS.getDfsIndex()); } else if (!dstDFS.isVisited()) { // make a DFS visit currIndex = dfsTraverse(currDFS.getDfsIndex(), currIndex, dstSw, dfsList, currSet); if (currIndex < 0) return -1; // update lowpoint after the visit if (dstDFS.getLowpoint() < currDFS.getLowpoint()) currDFS.setLowpoint(dstDFS.getLowpoint()); } // else, it is a node already visited with a higher // dfs index, just ignore. } } } // Add current node to currSet. currSet.add(currSw); // Cluster computation. // If the node's lowpoint is greater than its parent's DFS index, // we need to form a new cluster with all the switches in the // currSet. if (currDFS.getLowpoint() > currDFS.getParentDFSIndex()) { // The cluster thus far forms a strongly connected component. // create a new switch cluster and the switches in the current // set to the switch cluster. Cluster sc = new Cluster(); for(long sw: currSet){ sc.add(sw); switchClusterMap.put(sw, sc); } // delete all the nodes in the current set. currSet.clear(); // add the newly formed switch clusters to the cluster set. clusters.add(sc); } return currIndex; } /** * Go through every link and identify it is a blocked link or not. * If blocked, remove it from the switchport links and put them in the * blocked link category. * * Note that we do not update the tunnel ports and broadcast domain * port structures. We need those to still answer the question if the * ports are tunnel or broadcast domain ports. * * If we add additional ports to blocked ports later on, we may simply * call this method again to remove the links on the newly blocked ports. */ protected void removeLinksOnBlockedPorts() { Iterator nptIter; Iterator linkIter; // Iterate through all the links and all the switch ports // and move the links on blocked switch ports to blocked links nptIter = this.switchPortLinks.keySet().iterator(); while (nptIter.hasNext()) { NodePortTuple npt = nptIter.next(); linkIter = switchPortLinks.get(npt).iterator(); while (linkIter.hasNext()) { Link link = linkIter.next(); if (isBlockedLink(link)) { this.blockedLinks.add(link); linkIter.remove(); } } // Note that at this point, the switchport may have // no links in it. We could delete the switch port, // but we will leave it as is. } } public Set getBlockedPorts() { return this.blockedPorts; } protected Set getBlockedLinks() { return this.blockedLinks; } /** Returns true if a link has either one of its switch ports * blocked. * @param l * @return */ protected boolean isBlockedLink(Link l) { NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); return (isBlockedPort(n1) || isBlockedPort(n2)); } protected boolean isBlockedPort(NodePortTuple npt) { return blockedPorts.contains(npt); } protected boolean isTunnelPort(NodePortTuple npt) { return tunnelPorts.contains(npt); } protected boolean isTunnelLink(Link l) { NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); return (isTunnelPort(n1) || isTunnelPort(n2)); } public boolean isBroadcastDomainLink(Link l) { NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); return (isBroadcastDomainPort(n1) || isBroadcastDomainPort(n2)); } public boolean isBroadcastDomainPort(NodePortTuple npt) { return broadcastDomainPorts.contains(npt); } class NodeDist implements Comparable { private Long node; public Long getNode() { return node; } private int dist; public int getDist() { return dist; } public NodeDist(Long node, int dist) { this.node = node; this.dist = dist; } public int compareTo(NodeDist o) { if (o.dist == this.dist) { return (int)(o.node - this.node); } return o.dist - this.dist; } } protected BroadcastTree dijkstra(Cluster c, Long root, Map linkCost, boolean isDstRooted) { HashMap nexthoplinks = new HashMap(); //HashMap nexthopnodes = new HashMap(); HashMap cost = new HashMap(); int w; for (Long node: c.links.keySet()) { nexthoplinks.put(node, null); //nexthopnodes.put(node, null); cost.put(node, MAX_PATH_WEIGHT); } HashMap seen = new HashMap(); PriorityQueue nodeq = new PriorityQueue(); nodeq.add(new NodeDist(root, 0)); cost.put(root, 0); while (nodeq.peek() != null) { NodeDist n = nodeq.poll(); Long cnode = n.getNode(); int cdist = n.getDist(); if (cdist >= MAX_PATH_WEIGHT) break; if (seen.containsKey(cnode)) continue; seen.put(cnode, true); for (Link link: c.links.get(cnode)) { Long neighbor; if (isDstRooted == true) neighbor = link.getSrc(); else neighbor = link.getDst(); // links directed toward cnode will result in this condition // if (neighbor == cnode) continue; if (linkCost == null || linkCost.get(link)==null) w = 1; else w = linkCost.get(link); int ndist = cdist + w; // the weight of the link, always 1 in current version of floodlight. if (ndist < cost.get(neighbor)) { cost.put(neighbor, ndist); nexthoplinks.put(neighbor, link); //nexthopnodes.put(neighbor, cnode); nodeq.add(new NodeDist(neighbor, ndist)); } } } BroadcastTree ret = new BroadcastTree(nexthoplinks, cost); return ret; } protected void calculateShortestPathTreeInClusters() { pathcache.clear(); destinationRootedTrees.clear(); Map linkCost = new HashMap(); int tunnel_weight = switchPorts.size() + 1; for(NodePortTuple npt: tunnelPorts) { if (switchPortLinks.get(npt) == null) continue; for(Link link: switchPortLinks.get(npt)) { if (link == null) continue; linkCost.put(link, tunnel_weight); } } for(Cluster c: clusters) { for (Long node : c.links.keySet()) { BroadcastTree tree = dijkstra(c, node, linkCost, true); destinationRootedTrees.put(node, tree); } } } protected void calculateBroadcastTreeInClusters() { for(Cluster c: clusters) { // c.id is the smallest node that's in the cluster BroadcastTree tree = destinationRootedTrees.get(c.id); clusterBroadcastTrees.put(c.id, tree); } } protected void calculateBroadcastNodePortsInClusters() { clusterBroadcastTrees.clear(); calculateBroadcastTreeInClusters(); for(Cluster c: clusters) { // c.id is the smallest node that's in the cluster BroadcastTree tree = clusterBroadcastTrees.get(c.id); //log.info("Broadcast Tree {}", tree); Set nptSet = new HashSet(); Map links = tree.getLinks(); if (links == null) continue; for(long nodeId: links.keySet()) { Link l = links.get(nodeId); if (l == null) continue; NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple npt2 = new NodePortTuple(l.getDst(), l.getDstPort()); nptSet.add(npt1); nptSet.add(npt2); } clusterBroadcastNodePorts.put(c.id, nptSet); } } protected Route buildroute(RouteId id, long srcId, long dstId) { NodePortTuple npt; LinkedList switchPorts = new LinkedList(); if (destinationRootedTrees == null) return null; if (destinationRootedTrees.get(dstId) == null) return null; Map nexthoplinks = destinationRootedTrees.get(dstId).getLinks(); if (!switches.contains(srcId) || !switches.contains(dstId)) { // This is a switch that is not connected to any other switch // hence there was no update for links (and hence it is not // in the network) log.debug("buildroute: Standalone switch: {}", srcId); // The only possible non-null path for this case is // if srcId equals dstId --- and that too is an 'empty' path [] } else if ((nexthoplinks!=null) && (nexthoplinks.get(srcId)!=null)) { while (srcId != dstId) { Link l = nexthoplinks.get(srcId); npt = new NodePortTuple(l.getSrc(), l.getSrcPort()); switchPorts.addLast(npt); npt = new NodePortTuple(l.getDst(), l.getDstPort()); switchPorts.addLast(npt); srcId = nexthoplinks.get(srcId).getDst(); } } // else, no path exists, and path equals null Route result = null; if (switchPorts != null && !switchPorts.isEmpty()) result = new Route(id, switchPorts); if (log.isTraceEnabled()) { log.trace("buildroute: {}", result); } return result; } protected int getCost(long srcId, long dstId) { BroadcastTree bt = destinationRootedTrees.get(dstId); if (bt == null) return -1; return (bt.getCost(srcId)); } /* * Getter Functions */ protected Set getClusters() { return clusters; } // IRoutingEngineService interfaces protected boolean routeExists(long srcId, long dstId) { BroadcastTree bt = destinationRootedTrees.get(dstId); if (bt == null) return false; Link link = bt.getLinks().get(srcId); if (link == null) return false; return true; } protected Route getRoute(long srcId, short srcPort, long dstId, short dstPort) { // Return null the route source and desitnation are the // same switchports. if (srcId == dstId && srcPort == dstPort) return null; List nptList; NodePortTuple npt; Route r = getRoute(srcId, dstId); if (r == null && srcId != dstId) return null; if (r != null) { nptList= new ArrayList(r.getPath()); } else { nptList = new ArrayList(); } npt = new NodePortTuple(srcId, srcPort); nptList.add(0, npt); // add src port to the front npt = new NodePortTuple(dstId, dstPort); nptList.add(npt); // add dst port to the end RouteId id = new RouteId(srcId, dstId); r = new Route(id, nptList); return r; } protected Route getRoute(long srcId, long dstId) { RouteId id = new RouteId(srcId, dstId); Route result = null; if (pathcache.containsKey(id)) { result = pathcache.get(id); } else { result = buildroute(id, srcId, dstId); pathcache.put(id, result); } if (log.isTraceEnabled()) { log.trace("getRoute: {} -> {}", id, result); } return result; } protected BroadcastTree getBroadcastTreeForCluster(long clusterId){ Cluster c = switchClusterMap.get(clusterId); if (c == null) return null; return clusterBroadcastTrees.get(c.id); } // // ITopologyService interface method helpers. // protected boolean isInternalToOpenflowDomain(long switchid, short port) { return !isAttachmentPointPort(switchid, port); } public boolean isAttachmentPointPort(long switchid, short port) { NodePortTuple npt = new NodePortTuple(switchid, port); if (switchPortLinks.containsKey(npt)) return false; return true; } protected long getOpenflowDomainId(long switchId) { Cluster c = switchClusterMap.get(switchId); if (c == null) return switchId; return c.getId(); } protected long getL2DomainId(long switchId) { return getOpenflowDomainId(switchId); } protected Set getSwitchesInOpenflowDomain(long switchId) { Cluster c = switchClusterMap.get(switchId); if (c == null) return null; return (c.getNodes()); } protected boolean inSameOpenflowDomain(long switch1, long switch2) { Cluster c1 = switchClusterMap.get(switch1); Cluster c2 = switchClusterMap.get(switch2); if (c1 != null && c2 != null) return (c1.getId() == c2.getId()); return (switch1 == switch2); } public boolean isAllowed(long sw, short portId) { return true; } protected boolean isIncomingBroadcastAllowedOnSwitchPort(long sw, short portId) { if (isInternalToOpenflowDomain(sw, portId)) { long clusterId = getOpenflowDomainId(sw); NodePortTuple npt = new NodePortTuple(sw, portId); if (clusterBroadcastNodePorts.get(clusterId).contains(npt)) return true; else return false; } return true; } public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort) { if (isInternalToOpenflowDomain(newSw, newPort)) return true; return (oldSw == newSw && oldPort == newPort); } protected Set getBroadcastNodePortsInCluster(long sw) { long clusterId = getOpenflowDomainId(sw); return clusterBroadcastNodePorts.get(clusterId); } public boolean inSameBroadcastDomain(long s1, short p1, long s2, short p2) { return false; } public boolean inSameL2Domain(long switch1, long switch2) { return inSameOpenflowDomain(switch1, switch2); } public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort) { // Use this function to redirect traffic if needed. return new NodePortTuple(dst, dstPort); } public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort) { // Use this function to reinject traffic from a different port if needed. return new NodePortTuple(src, srcPort); } public Set getSwitches() { return switches; } public Set getPortsWithLinks(long sw) { return switchPorts.get(sw); } public Set getBroadcastPorts(long targetSw, long src, short srcPort) { Set result = new HashSet(); long clusterId = getOpenflowDomainId(targetSw); for(NodePortTuple npt: clusterBroadcastNodePorts.get(clusterId)) { if (npt.getNodeId() == targetSw) { result.add(npt.getPortId()); } } return result; } public NodePortTuple getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, short dstPort) { // TODO Auto-generated method stub return null; } public NodePortTuple getAllowedIncomingBroadcastPort(long src, short srcPort) { // TODO Auto-generated method stub return null; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/TopologyManager.java0000664000175000017500000012056012041336206031561 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.SingletonTask; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.packet.BSN; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.LLDP; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.web.TopologyWebRoutable; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.OFType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Topology manager is responsible for maintaining the controller's notion * of the network graph, as well as implementing tools for finding routes * through the topology. */ @LogMessageCategory("Network Topology") public class TopologyManager implements IFloodlightModule, ITopologyService, IRoutingService, ILinkDiscoveryListener, IOFMessageListener, IHAListener { protected static Logger log = LoggerFactory.getLogger(TopologyManager.class); public static final String CONTEXT_TUNNEL_ENABLED = "com.bigswitch.floodlight.topologymanager.tunnelEnabled"; /** * Set of ports for each switch */ protected Map> switchPorts; /** * Set of links organized by node port tuple */ protected Map> switchPortLinks; /** * Set of direct links */ protected Map> directLinks; /** * set of links that are broadcast domain links. */ protected Map> portBroadcastDomainLinks; /** * set of tunnel links */ protected Map> tunnelLinks; protected ILinkDiscoveryService linkDiscovery; protected IThreadPoolService threadPool; protected IFloodlightProviderService floodlightProvider; protected IRestApiService restApi; // Modules that listen to our updates protected ArrayList topologyAware; protected BlockingQueue ldUpdates; protected List appliedUpdates; // These must be accessed using getCurrentInstance(), not directly protected TopologyInstance currentInstance; protected TopologyInstance currentInstanceWithoutTunnels; protected SingletonTask newInstanceTask; private Date lastUpdateTime; /** * Flag that indicates if links (direct/tunnel/multihop links) were * updated as part of LDUpdate. */ protected boolean linksUpdated; /** * Flag that indicates if direct or tunnel links were updated as * part of LDUpdate. */ protected boolean dtLinksUpdated; /** * Thread for recomputing topology. The thread is always running, * however the function applyUpdates() has a blocking call. */ @LogMessageDoc(level="ERROR", message="Error in topology instance task thread", explanation="An unknown error occured in the topology " + "discovery module.", recommendation=LogMessageDoc.CHECK_CONTROLLER) protected class UpdateTopologyWorker implements Runnable { @Override public void run() { try { updateTopology(); } catch (Exception e) { log.error("Error in topology instance task thread", e); } } } public boolean updateTopology() { boolean newInstanceFlag; linksUpdated = false; dtLinksUpdated = false; applyUpdates(); newInstanceFlag = createNewInstance(); lastUpdateTime = new Date(); informListeners(); return newInstanceFlag; } // ********************** // ILinkDiscoveryListener // ********************** @Override public void linkDiscoveryUpdate(LDUpdate update) { boolean scheduleFlag = false; // if there's no udpates in the queue, then // we need to schedule an update. if (ldUpdates.peek() == null) scheduleFlag = true; if (log.isTraceEnabled()) { log.trace("Queuing update: {}", update); } ldUpdates.add(update); if (scheduleFlag) { newInstanceTask.reschedule(1, TimeUnit.MICROSECONDS); } } // **************** // ITopologyService // **************** // // ITopologyService interface methods // @Override public Date getLastUpdateTime() { return lastUpdateTime; } @Override public void addListener(ITopologyListener listener) { topologyAware.add(listener); } @Override public boolean isAttachmentPointPort(long switchid, short port) { return isAttachmentPointPort(switchid, port, true); } @Override public boolean isAttachmentPointPort(long switchid, short port, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); // if the port is not attachment point port according to // topology instance, then return false if (ti.isAttachmentPointPort(switchid, port) == false) return false; // Check whether the port is a physical port. We should not learn // attachment points on "special" ports. if ((port & 0xff00) == 0xff00 && port != (short)0xfffe) return false; // Make sure that the port is enabled. IOFSwitch sw = floodlightProvider.getSwitches().get(switchid); if (sw == null) return false; return (sw.portEnabled(port)); } public long getOpenflowDomainId(long switchId) { return getOpenflowDomainId(switchId, true); } public long getOpenflowDomainId(long switchId, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getOpenflowDomainId(switchId); } @Override public long getL2DomainId(long switchId) { return getL2DomainId(switchId, true); } @Override public long getL2DomainId(long switchId, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getL2DomainId(switchId); } @Override public boolean inSameOpenflowDomain(long switch1, long switch2) { return inSameOpenflowDomain(switch1, switch2, true); } @Override public boolean inSameOpenflowDomain(long switch1, long switch2, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.inSameOpenflowDomain(switch1, switch2); } @Override public boolean isAllowed(long sw, short portId) { return isAllowed(sw, portId, true); } @Override public boolean isAllowed(long sw, short portId, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.isAllowed(sw, portId); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @Override public boolean isIncomingBroadcastAllowed(long sw, short portId) { return isIncomingBroadcastAllowed(sw, portId, true); } public boolean isIncomingBroadcastAllowed(long sw, short portId, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** Get all the ports connected to the switch */ @Override public Set getPortsWithLinks(long sw) { return getPortsWithLinks(sw, true); } /** Get all the ports connected to the switch */ @Override public Set getPortsWithLinks(long sw, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getPortsWithLinks(sw); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** Get all the ports on the target switch (targetSw) on which a * broadcast packet must be sent from a host whose attachment point * is on switch port (src, srcPort). */ public Set getBroadcastPorts(long targetSw, long src, short srcPort) { return getBroadcastPorts(targetSw, src, srcPort, true); } /** Get all the ports on the target switch (targetSw) on which a * broadcast packet must be sent from a host whose attachment point * is on switch port (src, srcPort). */ public Set getBroadcastPorts(long targetSw, long src, short srcPort, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getBroadcastPorts(targetSw, src, srcPort); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort) { // Use this function to redirect traffic if needed. return getOutgoingSwitchPort(src, srcPort, dst, dstPort, true); } @Override public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled) { // Use this function to redirect traffic if needed. TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getOutgoingSwitchPort(src, srcPort, dst, dstPort); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort) { return getIncomingSwitchPort(src, srcPort, dst, dstPort, true); } @Override public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getIncomingSwitchPort(src, srcPort, dst, dstPort); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** * Checks if the two switchports belong to the same broadcast domain. */ @Override public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2) { return isInSameBroadcastDomain(s1, p1, s2, p2, true); } @Override public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.inSameBroadcastDomain(s1, p1, s2, p2); } /** * Checks if the switchport is a broadcast domain port or not. */ @Override public boolean isBroadcastDomainPort(long sw, short port) { return isBroadcastDomainPort(sw, port, true); } @Override public boolean isBroadcastDomainPort(long sw, short port, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.isBroadcastDomainPort(new NodePortTuple(sw, port)); } /** * Checks if the new attachment point port is consistent with the * old attachment point port. */ @Override public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort) { return isConsistent(oldSw, oldPort, newSw, newPort, true); } @Override public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.isConsistent(oldSw, oldPort, newSw, newPort); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /** * Checks if the two switches are in the same Layer 2 domain. */ @Override public boolean inSameL2Domain(long switch1, long switch2) { return inSameL2Domain(switch1, switch2, true); } @Override public boolean inSameL2Domain(long switch1, long switch2, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.inSameL2Domain(switch1, switch2); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, short dstPort) { return getAllowedOutgoingBroadcastPort(src, srcPort, dst, dstPort, true); } @Override public NodePortTuple getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled){ TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getAllowedOutgoingBroadcastPort(src, srcPort, dst, dstPort); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getAllowedIncomingBroadcastPort(long src, short srcPort) { return getAllowedIncomingBroadcastPort(src,srcPort, true); } @Override public NodePortTuple getAllowedIncomingBroadcastPort(long src, short srcPort, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getAllowedIncomingBroadcastPort(src,srcPort); } @Override public Set getBroadcastDomainPorts() { return portBroadcastDomainLinks.keySet(); } @Override public Set getTunnelPorts() { return tunnelLinks.keySet(); } @Override public Set getBlockedPorts() { Set bp; Set blockedPorts = new HashSet(); // As we might have two topologies, simply get the union of // both of them and send it. bp = getCurrentInstance(true).getBlockedPorts(); if (bp != null) blockedPorts.addAll(bp); bp = getCurrentInstance(false).getBlockedPorts(); if (bp != null) blockedPorts.addAll(bp); return blockedPorts; } @Override public List getLastLinkUpdates() { return appliedUpdates; } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // *************** // IRoutingService // *************** @Override public Route getRoute(long src, long dst) { return getRoute(src, dst, true); } @Override public Route getRoute(long src, long dst, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getRoute(src, dst); } @Override public Route getRoute(long src, short srcPort, long dst, short dstPort) { return getRoute(src, srcPort, dst, dstPort, true); } @Override public Route getRoute(long src, short srcPort, long dst, short dstPort, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.getRoute(src, srcPort, dst, dstPort); } @Override public boolean routeExists(long src, long dst) { return routeExists(src, dst, true); } @Override public boolean routeExists(long src, long dst, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); return ti.routeExists(src, dst); } // ****************** // IOFMessageListener // ****************** @Override public String getName() { return "topology"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return "linkdiscovery".equals(name); } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx); default: break; } return Command.CONTINUE; } // *************** // IHAListener // *************** @Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case MASTER: if (oldRole == Role.SLAVE) { log.debug("Re-computing topology due " + "to HA change from SLAVE->MASTER"); newInstanceTask.reschedule(1, TimeUnit.MILLISECONDS); } break; case SLAVE: log.debug("Clearing topology due to " + "HA change to SLAVE"); clearCurrentTopology(); break; default: break; } } @Override public void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { // no-op } // ***************** // IFloodlightModule // ***************** @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(ITopologyService.class); l.add(IRoutingService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(ITopologyService.class, this); m.put(IRoutingService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(ILinkDiscoveryService.class); l.add(IThreadPoolService.class); l.add(IFloodlightProviderService.class); l.add(ICounterStoreService.class); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class); threadPool = context.getServiceImpl(IThreadPoolService.class); floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); restApi = context.getServiceImpl(IRestApiService.class); switchPorts = new HashMap>(); switchPortLinks = new HashMap>(); directLinks = new HashMap>(); portBroadcastDomainLinks = new HashMap>(); tunnelLinks = new HashMap>(); topologyAware = new ArrayList(); ldUpdates = new LinkedBlockingQueue(); appliedUpdates = new ArrayList(); clearCurrentTopology(); } @Override public void startUp(FloodlightModuleContext context) { ScheduledExecutorService ses = threadPool.getScheduledExecutor(); newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker()); linkDiscovery.addListener(this); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addHAListener(this); addRestletRoutable(); } protected void addRestletRoutable() { restApi.addRestletRoutable(new TopologyWebRoutable()); } // **************** // Internal methods // **************** /** * If the packet-in switch port is disabled for all data traffic, then * the packet will be dropped. Otherwise, the packet will follow the * normal processing chain. * @param sw * @param pi * @param cntx * @return */ protected Command dropFilter(long sw, OFPacketIn pi, FloodlightContext cntx) { Command result = Command.CONTINUE; short port = pi.getInPort(); // If the input port is not allowed for data traffic, drop everything. // BDDP packets will not reach this stage. if (isAllowed(sw, port) == false) { if (log.isTraceEnabled()) { log.trace("Ignoring packet because of topology " + "restriction on switch={}, port={}", sw, port); result = Command.STOP; } } // if sufficient information is available, then drop broadcast // packets here as well. return result; } /** * TODO This method must be moved to a layer below forwarding * so that anyone can use it. * @param packetData * @param sw * @param ports * @param cntx */ @LogMessageDoc(level="ERROR", message="Failed to clear all flows on switch {switch}", explanation="An I/O error occured while trying send " + "topology discovery packet", recommendation=LogMessageDoc.CHECK_SWITCH) public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw, Set ports, FloodlightContext cntx) { if (ports == null) return; if (packetData == null || packetData.length <= 0) return; OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_OUT); List actions = new ArrayList(); for(short p: ports) { actions.add(new OFActionOutput(p, (short) 0)); } // set actions po.setActions(actions); // set action length po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size())); // set buffer-id to BUFFER_ID_NONE po.setBufferId(OFPacketOut.BUFFER_ID_NONE); // set in-port to OFPP_NONE po.setInPort(OFPort.OFPP_NONE.getValue()); // set packet data po.setPacketData(packetData); // compute and set packet length. short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length); po.setLength(poLength); try { //counterStore.updatePktOutFMCounterStore(sw, po); if (log.isTraceEnabled()) { log.trace("write broadcast packet on switch-id={} " + "interaces={} packet-data={} packet-out={}", new Object[] {sw.getId(), ports, packetData, po}); } sw.write(po, cntx); } catch (IOException e) { log.error("Failure writing packet out", e); } } /** * The BDDP packets are forwarded out of all the ports out of an * openflowdomain. Get all the switches in the same openflow * domain as the sw (disabling tunnels). Then get all the * external switch ports and send these packets out. * @param sw * @param pi * @param cntx */ protected void doFloodBDDP(long pinSwitch, OFPacketIn pi, FloodlightContext cntx) { TopologyInstance ti = getCurrentInstance(false); Set switches = ti.getSwitchesInOpenflowDomain(pinSwitch); if (switches == null) { // indicates no links are connected to the switches switches = new HashSet(); switches.add(pinSwitch); } for(long sid: switches) { IOFSwitch sw = floodlightProvider.getSwitches().get(sid); if (sw == null) continue; Collection enabledPorts = sw.getEnabledPortNumbers(); if (enabledPorts == null) continue; Set ports = new HashSet(); ports.addAll(enabledPorts); // all the ports known to topology // without tunnels. // out of these, we need to choose only those that are // broadcast port, otherwise, we should eliminate. Set portsKnownToTopo = ti.getPortsWithLinks(sid); if (portsKnownToTopo != null) { for(short p: portsKnownToTopo) { NodePortTuple npt = new NodePortTuple(sid, p); if (ti.isBroadcastDomainPort(npt) == false) { ports.remove(p); } } } // remove the incoming switch port if (pinSwitch == sid) { ports.remove(pi.getInPort()); } // we have all the switch ports to which we need to broadcast. doMultiActionPacketOut(pi.getPacketData(), sw, ports, cntx); } } protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { // get the packet-in switch. Ethernet eth = IFloodlightProviderService.bcStore. get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); if (eth.getEtherType() == Ethernet.TYPE_BSN) { BSN bsn = (BSN) eth.getPayload(); if (bsn == null) return Command.STOP; if (bsn.getPayload() == null) return Command.STOP; // It could be a packet other than BSN LLDP, therefore // continue with the regular processing. if (bsn.getPayload() instanceof LLDP == false) return Command.CONTINUE; doFloodBDDP(sw.getId(), pi, cntx); } else { return dropFilter(sw.getId(), pi, cntx); } return Command.STOP; } /** * Updates concerning switch disconnect and port down are not processed. * LinkDiscoveryManager is expected to process those messages and send * multiple link removed messages. However, all the updates from * LinkDiscoveryManager would be propagated to the listeners of topology. */ @LogMessageDoc(level="ERROR", message="Error reading link discovery update.", explanation="Unable to process link discovery update", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) public void applyUpdates() { appliedUpdates.clear(); LDUpdate update = null; while (ldUpdates.peek() != null) { try { update = ldUpdates.take(); } catch (Exception e) { log.error("Error reading link discovery update.", e); } if (log.isTraceEnabled()) { log.trace("Applying update: {}", update); } if (update.getOperation() == UpdateOperation.LINK_UPDATED) { addOrUpdateLink(update.getSrc(), update.getSrcPort(), update.getDst(), update.getDstPort(), update.getType()); } else if (update.getOperation() == UpdateOperation.LINK_REMOVED){ removeLink(update.getSrc(), update.getSrcPort(), update.getDst(), update.getDstPort()); } // Add to the list of applied updates. appliedUpdates.add(update); } } /** * This function computes a new topology. */ /** * This function computes a new topology instance. * It ignores links connected to all broadcast domain ports * and tunnel ports. The method returns if a new instance of * topology was created or not. */ protected boolean createNewInstance() { Set blockedPorts = new HashSet(); if (!linksUpdated) return false; Map> openflowLinks; openflowLinks = new HashMap>(switchPortLinks); // Remove all tunnel links. for(NodePortTuple npt: tunnelLinks.keySet()) { if (openflowLinks.get(npt) != null) openflowLinks.remove(npt); } // Remove all broadcast domain links. for(NodePortTuple npt: portBroadcastDomainLinks.keySet()) { if (openflowLinks.get(npt) != null) openflowLinks.remove(npt); } TopologyInstance nt = new TopologyInstance(switchPorts, blockedPorts, openflowLinks, portBroadcastDomainLinks.keySet(), tunnelLinks.keySet()); nt.compute(); // We set the instances with and without tunnels to be identical. // If needed, we may compute them differently. currentInstance = nt; currentInstanceWithoutTunnels = nt; return true; } public void informListeners() { for(int i=0; i()); } } private void addPortToSwitch(long s, short p) { addSwitch(s); switchPorts.get(s).add(p); } public boolean removeSwitchPort(long sw, short port) { Set linksToRemove = new HashSet(); NodePortTuple npt = new NodePortTuple(sw, port); if (switchPortLinks.containsKey(npt) == false) return false; linksToRemove.addAll(switchPortLinks.get(npt)); for(Link link: linksToRemove) { removeLink(link); } return true; } public boolean removeSwitch(long sid) { // Delete all the links in the switch, switch and all // associated data should be deleted. if (switchPorts.containsKey(sid) == false) return false; Set linksToRemove = new HashSet(); for(Short p: switchPorts.get(sid)) { NodePortTuple n1 = new NodePortTuple(sid, p); linksToRemove.addAll(switchPortLinks.get(n1)); } if (linksToRemove.isEmpty()) return false; for(Link link: linksToRemove) { removeLink(link); } return true; } /** * Add the given link to the data structure. Returns true if a link was * added. * @param s * @param l * @return */ private boolean addLinkToStructure(Map> s, Link l) { boolean result1 = false, result2 = false; NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); if (s.get(n1) == null) { s.put(n1, new HashSet()); } if (s.get(n2) == null) { s.put(n2, new HashSet()); } result1 = s.get(n1).add(l); result2 = s.get(n2).add(l); return (result1 || result2); } /** * Delete the given link from the data strucure. Returns true if the * link was deleted. * @param s * @param l * @return */ private boolean removeLinkFromStructure(Map> s, Link l) { boolean result1 = false, result2 = false; NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); if (s.get(n1) != null) { result1 = s.get(n1).remove(l); if (s.get(n1).isEmpty()) s.remove(n1); } if (s.get(n2) != null) { result2 = s.get(n2).remove(l); if (s.get(n2).isEmpty()) s.remove(n2); } return result1 || result2; } public void addOrUpdateLink(long srcId, short srcPort, long dstId, short dstPort, LinkType type) { boolean flag1 = false, flag2 = false; Link link = new Link(srcId, srcPort, dstId, dstPort); addPortToSwitch(srcId, srcPort); addPortToSwitch(dstId, dstPort); addLinkToStructure(switchPortLinks, link); if (type.equals(LinkType.MULTIHOP_LINK)) { addLinkToStructure(portBroadcastDomainLinks, link); flag1 = removeLinkFromStructure(tunnelLinks, link); flag2 = removeLinkFromStructure(directLinks, link); dtLinksUpdated = flag1 || flag2; } else if (type.equals(LinkType.TUNNEL)) { addLinkToStructure(tunnelLinks, link); removeLinkFromStructure(portBroadcastDomainLinks, link); removeLinkFromStructure(directLinks, link); dtLinksUpdated = true; } else if (type.equals(LinkType.DIRECT_LINK)) { addLinkToStructure(directLinks, link); removeLinkFromStructure(tunnelLinks, link); removeLinkFromStructure(portBroadcastDomainLinks, link); dtLinksUpdated = true; } linksUpdated = true; } public void removeLink(Link link) { boolean flag1 = false, flag2 = false; flag1 = removeLinkFromStructure(directLinks, link); flag2 = removeLinkFromStructure(tunnelLinks, link); linksUpdated = true; dtLinksUpdated = flag1 || flag2; removeLinkFromStructure(portBroadcastDomainLinks, link); removeLinkFromStructure(switchPortLinks, link); NodePortTuple srcNpt = new NodePortTuple(link.getSrc(), link.getSrcPort()); NodePortTuple dstNpt = new NodePortTuple(link.getDst(), link.getDstPort()); // Remove switch ports if there are no links through those switch ports if (switchPortLinks.get(srcNpt) == null) { if (switchPorts.get(srcNpt.getNodeId()) != null) switchPorts.get(srcNpt.getNodeId()).remove(srcNpt.getPortId()); } if (switchPortLinks.get(dstNpt) == null) { if (switchPorts.get(dstNpt.getNodeId()) != null) switchPorts.get(dstNpt.getNodeId()).remove(dstNpt.getPortId()); } // Remove the node if no ports are present if (switchPorts.get(srcNpt.getNodeId())!=null && switchPorts.get(srcNpt.getNodeId()).isEmpty()) { switchPorts.remove(srcNpt.getNodeId()); } if (switchPorts.get(dstNpt.getNodeId())!=null && switchPorts.get(dstNpt.getNodeId()).isEmpty()) { switchPorts.remove(dstNpt.getNodeId()); } } public void removeLink(long srcId, short srcPort, long dstId, short dstPort) { Link link = new Link(srcId, srcPort, dstId, dstPort); removeLink(link); } public void clear() { switchPorts.clear(); switchPortLinks.clear(); portBroadcastDomainLinks.clear(); tunnelLinks.clear(); directLinks.clear(); appliedUpdates.clear(); } /** * Clears the current topology. Note that this does NOT * send out updates. */ public void clearCurrentTopology() { this.clear(); linksUpdated = true; dtLinksUpdated = true; createNewInstance(); lastUpdateTime = new Date(); } /** * Getters. No Setters. */ public Map> getSwitchPorts() { return switchPorts; } public Map> getSwitchPortLinks() { return switchPortLinks; } public Map> getPortBroadcastDomainLinks() { return portBroadcastDomainLinks; } public TopologyInstance getCurrentInstance(boolean tunnelEnabled) { if (tunnelEnabled) return currentInstance; else return this.currentInstanceWithoutTunnels; } public TopologyInstance getCurrentInstance() { return this.getCurrentInstance(true); } /** * Switch methods */ public Set getPorts(long sw) { Set ports = new HashSet(); IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) return null; Collection ofpList = iofSwitch.getEnabledPortNumbers(); if (ofpList == null) return null; Set qPorts = linkDiscovery.getQuarantinedPorts(sw); if (qPorts != null) ofpList.removeAll(qPorts); ports.addAll(ofpList); return ports; } } floodlight-0.90/src/main/java/net/floodlightcontroller/topology/ITopologyListener.java0000664000175000017500000000026612041336206032105 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; public interface ITopologyListener { /** * Happens when the switch clusters are recomputed */ void topologyChanged(); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/0000775000175000017500000000000012041336206025373 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/storage/IStorageSourceService.java0000664000175000017500000003131612041336206032461 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import net.floodlightcontroller.core.module.IFloodlightService; public interface IStorageSourceService extends IFloodlightService { /** Set the column to be used as the primary key for a table. This should * be guaranteed to be unique for all of the rows in the table, although the * storage API does not necessarily enforce this requirement. If no primary * key name is specified for a table then the storage API assumes there is * a column named "id" that is used as the primary key. In this case when * a new row is inserted using the storage API and no id is specified * explictly in the row data, the storage API automatically generates a * unique ID (typically a UUID) for the id column. To work across all * possible implementations of the storage API it is safest, though, to * specify the primary key column explicitly. * FIXME: It's sort of a kludge to have to specify the primary key column * here. Ideally there would be some sort of metadata -- perhaps stored * directly in the table, at least in the NoSQL case -- that the * storage API could query to obtain the primary key info. * @param tableName The name of the table for which we're setting the key * @param primaryKeyName The name of column to be used as the primary key */ public void setTablePrimaryKeyName(String tableName, String primaryKeyName); /** Create a new table if one does not already exist with the given name. * * @param tableName The name of the table to create. * @param indexedColumns Which columns should be indexed */ void createTable(String tableName, Set indexedColumns); /** * @return the set of all tables that have been created via createTable */ Set getAllTableNames(); /** Create a query object representing the given query parameters. The query * object can be passed to executeQuery to actually perform the query and obtain * a result set. * * @param tableName The name of the table to query. * @param columnNames The list of columns to return in the result set. * @param predicate The predicate that specifies which rows to return in the result set. * @param ordering Specification of order that rows are returned from the result set * returned from executing the query. If the ordering is null, then rows are returned * in an implementation-specific order. * @return Query object to be passed to executeQuery. */ IQuery createQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering); /** Execute a query created with createQuery. * * @param query The query to execute * @return The result set containing the rows/columns specified in the query. */ IResultSet executeQuery(IQuery query); /** Execute a query created with the given query parameters. * * @param tableName The name of the table to query. * @param columnNames The list of columns to return in the result set. * @param predicate The predicate that specifies which rows to return in the result set. * @param ordering Specification of order that rows are returned from the result set * returned from executing the query. If the ordering is null, then rows are returned * in an implementation-specific order. * @return The result set containing the rows/columns specified in the query. */ IResultSet executeQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering); /** Execute a query and call the row mapper to map the results to Java objects. * * @param tableName The name of the table to query. * @param columnNames The list of columns to return in the result set. * @param predicate The predicate that specifies which rows to return in the result set. * @param ordering Specification of order that rows are returned from the result set * returned from executing the query. If the ordering is null, then rows are returned * in an implementation-specific order. * @param rowMapper The client-supplied object that maps the data in a row in the result * set to a client object. * @return The result set containing the rows/columns specified in the query. */ Object[] executeQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering, IRowMapper rowMapper); /** Insert a new row in the table with the given column data. * If the primary key is the default value of "id" and is not specified in the * then a unique id will be automatically assigned to the row. * @param tableName The name of the table to which to add the row * @param values The map of column names/values to add to the table. */ void insertRow(String tableName, Map values); /** Update or insert a list of rows in the table. * The primary key must be included in the map of values for each row. * @param tableName The table to update or insert into * @param values The map of column names/values to update the rows */ void updateRows(String tableName, List> rows); /** Update the rows in the given table. Any rows matching the predicate * are updated with the column names/values specified in the values map. * (The values map should not contain the special column "id".) * @param tableName The table to update * @param predicate The predicate to use to select which rows to update * @param values The map of column names/values to update the rows. */ void updateMatchingRows(String tableName, IPredicate predicate, Map values); /** Update or insert a row in the table with the given row key (primary * key) and column names/values. (If the values map contains the special * column "id", its value must match rowId.) * @param tableName The table to update or insert into * @param rowKey The ID (primary key) of the row to update * @param values The map of column names/values to update the rows */ void updateRow(String tableName, Object rowKey, Map values); /** Update or insert a row in the table with the given column data. * The primary key must be included in the map of values. * @param tableName The table to update or insert into * @param values The map of column names/values to update the rows */ void updateRow(String tableName, Map values); /** Delete the row with the given primary key. * * @param tableName The table from which to delete the row * @param rowKey The primary key of the row to delete. */ void deleteRow(String tableName, Object rowKey); /** Delete the rows with the given keys. * * @param tableName The table from which to delete the rows * @param rowKeys The set of primary keys of the rows to delete. */ void deleteRows(String tableName, Set rowKeys); /** * Delete the rows that match the predicate * @param tableName * @param predicate */ void deleteMatchingRows(String tableName, IPredicate predicate); /** Query for a row with the given ID (primary key). * * @param tableName The name of the table to query * @param rowKey The primary key of the row * @return The result set containing the row with the given ID */ IResultSet getRow(String tableName, Object rowKey); /** * Set exception handler to use for asynchronous operations. * @param exceptionHandler */ void setExceptionHandler(IStorageExceptionHandler exceptionHandler); /** * Asynchronous variant of executeQuery. * * @param query * @return */ public Future executeQueryAsync(final IQuery query); /** * Asynchronous variant of executeQuery. * * @param tableName * @param columnNames * @param predicate * @param ordering * @return */ public Future executeQueryAsync(final String tableName, final String[] columnNames, final IPredicate predicate, final RowOrdering ordering); /** * Asynchronous variant of executeQuery * * @param tableName * @param columnNames * @param predicate * @param ordering * @param rowMapper * @return */ public Future executeQueryAsync(final String tableName, final String[] columnNames, final IPredicate predicate, final RowOrdering ordering, final IRowMapper rowMapper); /** * Asynchronous variant of insertRow. * * @param tableName * @param values * @return */ public Future insertRowAsync(final String tableName, final Map values); /** * Asynchronous variant of updateRows * @param tableName * @param rows */ public Future updateRowsAsync(final String tableName, final List> rows); /** * Asynchronous variant of updateMatchingRows * * @param tableName * @param predicate * @param values * @return */ public Future updateMatchingRowsAsync(final String tableName, final IPredicate predicate, final Map values); /** * Asynchronous variant of updateRow * * @param tableName * @param rowKey * @param values * @return */ public Future updateRowAsync(final String tableName, final Object rowKey, final Map values); /** * Asynchronous version of updateRow * * @param tableName * @param values * @return */ public Future updateRowAsync(final String tableName, final Map values); /** * Asynchronous version of deleteRow * * @param tableName * @param rowKey * @return */ public Future deleteRowAsync(final String tableName, final Object rowKey); /** * Asynchronous version of deleteRows * * @param tableName * @param rowKeys * @return */ public Future deleteRowsAsync(final String tableName, final Set rowKeys); /** * Asynchronous version of deleteRows * * @param tableName * @param predicate * @return */ public Future deleteMatchingRowsAsync(final String tableName, final IPredicate predicate); /** * Asynchronous version of getRow * * @param tableName * @param rowKey * @return */ public Future getRowAsync(final String tableName, final Object rowKey); /** * Asynchronous version of save * * @param resultSet * @return */ public Future saveAsync(final IResultSet resultSet); /** Add a listener to the specified table. The listener is called * when any modifications are made to the table. You can add the same * listener instance to multiple tables, since the table name is * included as a parameter in the listener methods. * @param tableName The name of the table to listen for modifications * @param listener The listener instance to call */ public void addListener(String tableName, IStorageSourceListener listener); /** Remove a listener from the specified table. The listener should * have been previously added to the table with addListener. * @param tableName The name of the table with the listener * @param listener The previously installed listener instance */ public void removeListener(String tableName, IStorageSourceListener listener); /** This is logically a private method and should not be called by * clients of this interface. * @param notifications the notifications to dispatch */ public void notifyListeners(List notifications); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/ResultSetIterator.java0000664000175000017500000000365412041336206031712 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.Iterator; import java.util.NoSuchElementException; /** Iterator wrapper for an IResultSet, useful for iterating through query * results in an enhanced for (foreach) loop. * * Note that the iterator manipulates the state of the underlying IResultSet. */ public class ResultSetIterator implements Iterator { private IResultSet resultSet; private boolean hasAnother; private boolean peekedAtNext; public ResultSetIterator(IResultSet resultSet) { this.resultSet = resultSet; this.peekedAtNext = false; } @Override public IResultSet next() { if (!peekedAtNext) { hasAnother = resultSet.next(); } peekedAtNext = false; if (!hasAnother) throw new NoSuchElementException(); return resultSet; } @Override public boolean hasNext() { if (!peekedAtNext) { hasAnother = resultSet.next(); peekedAtNext = true; } return hasAnother; } /** Row removal is not supported; use IResultSet.deleteRow instead. */ @Override public void remove() { throw new UnsupportedOperationException(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/nosql/0000775000175000017500000000000012041336206026527 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/storage/nosql/NoSqlQuery.java0000664000175000017500000000436412041336206031463 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.nosql; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.storage.IPredicate; import net.floodlightcontroller.storage.IQuery; import net.floodlightcontroller.storage.RowOrdering; public class NoSqlQuery implements IQuery { private String tableName; private String[] columnNameList; private IPredicate predicate; private RowOrdering rowOrdering; private Map> parameterMap; NoSqlQuery(String className, String[] columnNameList, IPredicate predicate, RowOrdering rowOrdering) { this.tableName = className; this.columnNameList = columnNameList; this.predicate = predicate; this.rowOrdering = rowOrdering; } @Override public void setParameter(String name, Object value) { if (parameterMap == null) parameterMap = new HashMap>(); parameterMap.put(name, (Comparable)value); } @Override public String getTableName() { return tableName; } String[] getColumnNameList() { return columnNameList; } IPredicate getPredicate() { return predicate; } RowOrdering getRowOrdering() { return rowOrdering; } Comparable getParameter(String name) { Comparable value = null; if (parameterMap != null) { value = parameterMap.get(name); } return value; } Map> getParameterMap() { return parameterMap; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/nosql/NoSqlResultSet.java0000664000175000017500000003260512041336206032307 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.nosql; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.TimeZone; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.NullValueStorageException; import net.floodlightcontroller.storage.ResultSetIterator; import net.floodlightcontroller.storage.StorageException; import net.floodlightcontroller.storage.TypeMismatchStorageException; public class NoSqlResultSet implements IResultSet { NoSqlStorageSource storageSource; String tableName; String primaryKeyName; List> rowList; int currentIndex; Map currentRowUpdate; List> rowUpdateList; Set rowDeleteSet; Iterator resultSetIterator; NoSqlResultSet(NoSqlStorageSource storageSource, String tableName, List> rowList) { this.storageSource = storageSource; this.primaryKeyName = storageSource.getTablePrimaryKeyName(tableName); this.tableName = tableName; if (rowList == null) rowList = new ArrayList>(); this.rowList = rowList; currentIndex = -1; } void addRow(Map row) { rowList.add(row); } @Override public Map getRow() { if ((currentIndex < 0) || (currentIndex >= rowList.size())) { throw new StorageException("No current row in result set."); } return rowList.get(currentIndex); } @Override public boolean containsColumn(String columnName) { return getObject(columnName) != null; } @Override public void close() { } private void endCurrentRowUpdate() { if (currentRowUpdate != null) { if (rowUpdateList == null) rowUpdateList = new ArrayList>(); rowUpdateList.add(currentRowUpdate); currentRowUpdate = null; } } @Override public boolean next() { endCurrentRowUpdate(); currentIndex++; return currentIndex < rowList.size(); } @Override public void save() { endCurrentRowUpdate(); if (rowUpdateList != null) { storageSource.updateRows(tableName, rowUpdateList); rowUpdateList = null; } if (rowDeleteSet != null) { storageSource.deleteRows(tableName, rowDeleteSet); rowDeleteSet = null; } } Object getObject(String columnName) { Map row = rowList.get(currentIndex); Object value = row.get(columnName); return value; } @Override public boolean getBoolean(String columnName) { Boolean b = getBooleanObject(columnName); if (b == null) throw new NullValueStorageException(columnName); return b.booleanValue(); } @Override public byte getByte(String columnName) { Byte b = getByteObject(columnName); if (b == null) throw new NullValueStorageException(columnName); return b.byteValue(); } @Override public byte[] getByteArray(String columnName) { byte[] b = null; Object obj = getObject(columnName); if (obj != null) { if (!(obj instanceof byte[])) throw new StorageException("Invalid byte array value"); b = (byte[])obj; } return b; } @Override public double getDouble(String columnName) { Double d = getDoubleObject(columnName); if (d == null) throw new NullValueStorageException(columnName); return d.doubleValue(); } @Override public float getFloat(String columnName) { Float f = getFloatObject(columnName); if (f == null) throw new NullValueStorageException(columnName); return f.floatValue(); } @Override public int getInt(String columnName) { Integer i = getIntegerObject(columnName); if (i == null) throw new NullValueStorageException(columnName); return i.intValue(); } @Override public long getLong(String columnName) { Long l = getLongObject(columnName); if (l == null) throw new NullValueStorageException(columnName); return l.longValue(); } @Override public short getShort(String columnName) { Short s = getShortObject(columnName); if (s == null) throw new NullValueStorageException(columnName); return s.shortValue(); } @Override public String getString(String columnName) { Object obj = getObject(columnName); if (obj == null) return null; return obj.toString(); } @Override public Date getDate(String column) { Date d; Object obj = getObject(column); if (obj == null) { d = null; } else if (obj instanceof Date) { d = (Date) obj; } else { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); try { d = dateFormat.parse(obj.toString()); } catch (ParseException exc) { throw new TypeMismatchStorageException(Date.class.getName(), obj.getClass().getName(), column); } } return d; } @Override public Short getShortObject(String columnName) { Short s; Object obj = getObject(columnName); if (obj instanceof Short) { s = (Short)obj; } else if (obj != null) { try { s = Short.parseShort(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Short.class.getName(), obj.getClass().getName(), columnName); } } else { s = null; } return s; } @Override public Integer getIntegerObject(String columnName) { Integer i; Object obj = getObject(columnName); if (obj instanceof Integer) { i = (Integer)obj; } else if (obj != null) { try { i = Integer.parseInt(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Integer.class.getName(), obj.getClass().getName(), columnName); } } else { i = null; } return i; } @Override public Long getLongObject(String columnName) { Long l; Object obj = getObject(columnName); if (obj instanceof Long) { l = (Long)obj; } else if (obj != null) { try { l = Long.parseLong(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Long.class.getName(), obj.getClass().getName(), columnName); } } else { l = null; } return l; } @Override public Float getFloatObject(String columnName) { Float f; Object obj = getObject(columnName); if (obj instanceof Float) { f = (Float)obj; } else if (obj != null) { try { f = Float.parseFloat(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Float.class.getName(), obj.getClass().getName(), columnName); } } else { f = null; } return f; } @Override public Double getDoubleObject(String columnName) { Double d; Object obj = getObject(columnName); if (obj instanceof Double) { d = (Double)obj; } else if (obj != null) { try { d = Double.parseDouble(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Double.class.getName(), obj.getClass().getName(), columnName); } } else { d = null; } return d; } @Override public Boolean getBooleanObject(String columnName) { Boolean b; Object obj = getObject(columnName); if (obj instanceof Boolean) { b = (Boolean)obj; } else if (obj != null) { try { b = Boolean.parseBoolean(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Boolean.class.getName(), obj.getClass().getName(), columnName); } } else { b = null; } return b; } @Override public Byte getByteObject(String columnName) { Byte b; Object obj = getObject(columnName); if (obj instanceof Byte) { b = (Byte)obj; } else if (obj != null) { try { b = Byte.parseByte(obj.toString()); } catch (NumberFormatException exc) { throw new TypeMismatchStorageException(Byte.class.getName(), obj.getClass().getName(), columnName); } } else { b = null; } return b; } @Override public boolean isNull(String columnName) { Object obj = getObject(columnName); return (obj == null); } private void addRowUpdate(String column, Object value) { if (currentRowUpdate == null) { currentRowUpdate = new HashMap(); Object key = rowList.get(currentIndex).get(primaryKeyName); currentRowUpdate.put(primaryKeyName, key); } currentRowUpdate.put(column, value); } @Override public void setBoolean(String columnName, boolean value) { addRowUpdate(columnName, value); } @Override public void setByte(String columnName, byte value) { addRowUpdate(columnName, value); } @Override public void setByteArray(String columnName, byte[] byteArray) { addRowUpdate(columnName, byteArray); } @Override public void setDouble(String columnName, double value) { addRowUpdate(columnName, value); } @Override public void setFloat(String columnName, float value) { addRowUpdate(columnName, value); } @Override public void setInt(String columnName, int value) { addRowUpdate(columnName, value); } @Override public void setLong(String columnName, long value) { addRowUpdate(columnName, value); } @Override public void setShort(String columnName, short value) { addRowUpdate(columnName, value); } @Override public void setString(String columnName, String value) { addRowUpdate(columnName, value); } @Override public void setShortObject(String columnName, Short value) { addRowUpdate(columnName, value); } @Override public void setIntegerObject(String columnName, Integer value) { addRowUpdate(columnName, value); } @Override public void setLongObject(String columnName, Long value) { addRowUpdate(columnName, value); } @Override public void setFloatObject(String columnName, Float value) { addRowUpdate(columnName, value); } @Override public void setDoubleObject(String columnName, Double value) { addRowUpdate(columnName, value); } @Override public void setBooleanObject(String columnName, Boolean value) { addRowUpdate(columnName, value); } @Override public void setByteObject(String columnName, Byte value) { addRowUpdate(columnName, value); } @Override public void setDate(String column, Date value) { addRowUpdate(column, value); } public void setNull(String columnName) { addRowUpdate(columnName, null); } @Override public void deleteRow() { Object key = (String) rowList.get(currentIndex).get(primaryKeyName); if (rowDeleteSet == null) rowDeleteSet = new HashSet(); rowDeleteSet.add(key); } @Override public Iterator iterator() { if (resultSetIterator == null) resultSetIterator = new ResultSetIterator(this); return resultSetIterator; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/nosql/NoSqlStorageSource.java0000664000175000017500000010324612041336206033142 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.nosql; import java.lang.Class; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.storage.AbstractStorageSource; import net.floodlightcontroller.storage.CompoundPredicate; import net.floodlightcontroller.storage.IPredicate; import net.floodlightcontroller.storage.IQuery; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.OperatorPredicate; import net.floodlightcontroller.storage.RowOrdering; import net.floodlightcontroller.storage.StorageException; import net.floodlightcontroller.storage.StorageSourceNotification; import net.floodlightcontroller.storage.TypeMismatchStorageException; public abstract class NoSqlStorageSource extends AbstractStorageSource { protected static Logger log = LoggerFactory.getLogger(NoSqlStorageSource.class); public enum ColumnIndexMode { NOT_INDEXED, RANGE_INDEXED, EQUALITY_INDEXED }; protected static final String DEFAULT_PRIMARY_KEY_NAME = "id"; private Map tablePrimaryKeyMap = new HashMap(); private Map> tableIndexedColumnMap = new HashMap>(); abstract class NoSqlPredicate { public boolean incorporateComparison(String columnName, OperatorPredicate.Operator operator, Comparable value, CompoundPredicate.Operator parentOperator) { return false; } public boolean canExecuteEfficiently() { return false; } public List> execute(String[] columnNames) { assert(false); return null; } abstract public boolean matchesRow(Map row); } @SuppressWarnings({ "unchecked", "rawtypes" }) class NoSqlRangePredicate extends NoSqlPredicate { NoSqlStorageSource storageSource; String tableName; String columnName; Comparable startValue; boolean startInclusive; Comparable endValue; boolean endInclusive; NoSqlRangePredicate(NoSqlStorageSource storageSource, String tableName, String columnName, Comparable startValue, boolean startInclusive, Comparable endValue, boolean endInclusive) { this.storageSource = storageSource; this.tableName = tableName; this.columnName = columnName; this.startValue = startValue; this.startInclusive = startInclusive; this.endValue = endValue; this.endInclusive = endInclusive; } public boolean incorporateComparison(String columnName, OperatorPredicate.Operator operator, Comparable value, CompoundPredicate.Operator parentOperator) { assert(operator != null); assert(parentOperator != null); // Must be the same column to incorporate if (!this.columnName.equals(columnName)) return false; // The only time we allow a null value is if it's an EQ operator. // In that case we can only incorporate if this predicate is also // a null equality predicate. if (value == null) { return ((operator == OperatorPredicate.Operator.EQ) && (startValue == null) && (endValue == null) && startInclusive && endInclusive); } // Don't incorporate parameterized values if (value instanceof String) { String s = (String)value; if (s.startsWith("?") && s.endsWith("?")) { return false; } } if (parentOperator == CompoundPredicate.Operator.AND) { switch (operator) { case EQ: if (matchesValue(value)) { startValue = endValue = value; startInclusive = endInclusive = true; return true; } break; case LT: if ((endValue == null) || (((Comparable)value).compareTo(endValue) <= 0)) { endValue = value; endInclusive = false; return true; } break; case LTE: if ((endValue == null) || (((Comparable)value).compareTo(endValue) < 0)) { endValue = value; endInclusive = true; return true; } break; case GT: if ((startValue == null) || (((Comparable)value).compareTo(startValue) >= 0)) { startValue = value; startInclusive = false; return true; } break; case GTE: if ((startValue == null) || (((Comparable)value).compareTo(startValue) > 0)) { startValue = value; startInclusive = true; return true; } break; } } else { switch (operator) { case EQ: if (matchesValue(value)) return true; break; case LT: if ((endValue == null) || (((Comparable)value).compareTo(endValue) > 0)) { endValue = value; endInclusive = false; return true; } break; case LTE: if ((endValue == null) || (((Comparable)value).compareTo(endValue) >= 0)) { endValue = value; endInclusive = true; return true; } break; case GT: if ((startValue == null) || (((Comparable)value).compareTo(startValue) < 0)) { startValue = value; startInclusive = false; return true; } break; case GTE: if ((startValue == null) || (((Comparable)value).compareTo(startValue) <= 0)) { startValue = value; startInclusive = true; return true; } break; } } return false; } private boolean isEqualityRange() { return (startValue == endValue) && startInclusive && endInclusive; } public boolean canExecuteEfficiently() { ColumnIndexMode indexMode = storageSource.getColumnIndexMode(tableName, columnName); switch (indexMode) { case NOT_INDEXED: return false; case RANGE_INDEXED: return true; case EQUALITY_INDEXED: return isEqualityRange(); } return true; } public List> execute(String columnNameList[]) { List> rowList; if (isEqualityRange()) rowList = storageSource.executeEqualityQuery(tableName, columnNameList, columnName, startValue); else rowList = storageSource.executeRangeQuery(tableName, columnNameList, columnName, startValue, startInclusive, endValue, endInclusive); return rowList; } Comparable coerceValue(Comparable value, Class targetClass) { if (value == null) return null; if (value.getClass() == targetClass) return value; // FIXME: For now we convert by first converting the source value to a // string and then converting to the target type. This logic probably needs // another pass to make it more robust/optimized. String s = value.toString(); Comparable obj = null; try { if (targetClass == Integer.class) { obj = new Integer(s); } else if (targetClass == Long.class) { obj = new Long(s); } else if (targetClass == Short.class) { obj = new Short(s); } else if (targetClass == Boolean.class) { obj = new Boolean(s); } else if (targetClass == Float.class) { obj = new Float(s); } else if (targetClass == Double.class) { obj = new Double(s); } else if (targetClass == Byte.class) { obj = new Byte(s); } else if (targetClass == String.class) { obj = s; } else if (targetClass == Date.class) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); try { obj = dateFormat.parse(s); } catch (ParseException exc) { throw new TypeMismatchStorageException(Date.class.getName(), value.getClass().getName(), "???"); } } } catch (Exception exc) { // Ignore the exception here. In this case obj will not be set, so we'll // throw the StorageException below when we check for a null obj. } if (obj == null) throw new StorageException("Column value could not be coerced to the correct type"); return obj; } boolean matchesValue(Comparable value) { boolean isNullEqPredicate = (startValue == null) && (endValue == null) && startInclusive && endInclusive; if (value == null) return isNullEqPredicate; if (isNullEqPredicate) return false; int result; Comparable coercedValue; if (startValue != null) { coercedValue = coerceValue(value, startValue.getClass()); result = ((Comparable)coercedValue).compareTo(startValue); if ((result < 0) || (!startInclusive && (result == 0))) return false; } if (endValue != null) { coercedValue = coerceValue(value, endValue.getClass()); result = ((Comparable)coercedValue).compareTo(endValue); if ((result > 0) || (!endInclusive && (result == 0))) return false; } return true; } public boolean matchesRow(Map row) { Comparable value = (Comparable)row.get(columnName); return matchesValue(value); } } class NoSqlOperatorPredicate extends NoSqlPredicate { NoSqlStorageSource storageSource; String columnName; OperatorPredicate.Operator operator; Object value; NoSqlOperatorPredicate(NoSqlStorageSource storageSource, String columnName, OperatorPredicate.Operator operator, Object value) { this.storageSource = storageSource; this.columnName = columnName; this.operator = operator; this.value = value; } public boolean incorporateComparison(String columnName, OperatorPredicate.Operator operator, Comparable value, CompoundPredicate.Operator parentOperator) { return false; } public boolean canExecuteEfficiently() { return false; } public List> execute(String columnNames[]) { throw new StorageException("Unimplemented predicate."); } public boolean matchesRow(Map row) { return false; } } class NoSqlCompoundPredicate extends NoSqlPredicate { NoSqlStorageSource storageSource; CompoundPredicate.Operator operator; boolean negated; List predicateList; NoSqlCompoundPredicate(NoSqlStorageSource storageSource, CompoundPredicate.Operator operator, boolean negated, List predicateList) { this.storageSource = storageSource; this.operator = operator; this.negated = negated; this.predicateList = predicateList; } public boolean incorporateComparison(String columnName, OperatorPredicate.Operator operator, Comparable value, CompoundPredicate.Operator parentOperator) { // It may be possible to incorporate other operator predicate into this one, // but it would need to take into account the negated attribute and I'd need // to think about it some more to make sure it was correct, so for now we just // disallow incorporation //if (parentOperator == this.operator) { // for (NoSqlPredicate predicate: predicateList) { // if (predicate.incorporateComparison(columnName, operator, value, parentOperator)) // return true; // } //} return false; } public boolean canExecuteEfficiently() { if (operator == CompoundPredicate.Operator.AND) { for (NoSqlPredicate predicate: predicateList) { if (predicate.canExecuteEfficiently()) { return true; } } return false; } else { for (NoSqlPredicate predicate: predicateList) { if (!predicate.canExecuteEfficiently()) { return false; } } return true; } } @SuppressWarnings({ "unchecked", "rawtypes" }) class RowComparator implements Comparator> { private String primaryKeyName; public RowComparator(String primaryKeyName) { this.primaryKeyName = primaryKeyName; } public int compare(Map row1, Map row2) { Comparable key1 = (Comparable)row1.get(primaryKeyName); Comparable key2 = (Comparable)row2.get(primaryKeyName); return key1.compareTo(key2); } public boolean equals(Object obj) { if (!(obj instanceof RowComparator)) return false; RowComparator rc = (RowComparator)obj; if (rc.primaryKeyName == null) return this.primaryKeyName == null; return rc.primaryKeyName.equals(this.primaryKeyName); } } @SuppressWarnings({ "unchecked", "rawtypes" }) private List> combineRowLists(String primaryKeyName, List> list1, List> list2, CompoundPredicate.Operator operator) { ArrayList> combinedRowList = new ArrayList>(); RowComparator rc = new RowComparator(primaryKeyName); Collections.sort(list1, rc); Collections.sort(list2,rc); Iterator> iterator1 = list1.iterator(); Iterator> iterator2 = list2.iterator(); boolean update1 = true; boolean update2 = true; Map row1 = null; Map row2 = null; Comparable key1 = null; Comparable key2 = null; while (true) { if (update1) { if (iterator1.hasNext()) { row1 = iterator1.next(); key1 = (Comparable)row1.get(primaryKeyName); } else { row1 = null; } } if (update2) { if (iterator2.hasNext()) { row2 = iterator1.next(); key2 = (Comparable)row2.get(primaryKeyName); } else { row2 = null; } } if (operator == CompoundPredicate.Operator.AND) { if ((row1 == null) || (row2 == null)) break; if (key1.equals(key2)) combinedRowList.add(row1); } else { if (row1 == null) { if (row2 == null) break; combinedRowList.add(row2); } else if ((row2 == null) || (((Comparable)key1).compareTo(key2) <= 0)) { combinedRowList.add(row2); } else { combinedRowList.add(row1); } } update1 = (key2 == null) || (((Comparable)key1).compareTo(key2) <= 0); update2 = (key1 == null) || (((Comparable)key2).compareTo(key1) <= 0); } return combinedRowList; } public List> execute(String columnNames[]) { List> combinedRowList = null; for (NoSqlPredicate predicate: predicateList) { List> rowList = predicate.execute(columnNames); if (combinedRowList != null) { combinedRowList = combineRowLists("id", combinedRowList, rowList, operator); } else { combinedRowList = rowList; } } return combinedRowList; } public boolean matchesRow(Map row) { if (operator == CompoundPredicate.Operator.AND) { for (NoSqlPredicate predicate : predicateList) { if (!predicate.matchesRow(row)) { return false; } } return true; } else { for (NoSqlPredicate predicate : predicateList) { if (predicate.matchesRow(row)) { return true; } } return false; } } } public NoSqlStorageSource() { super(); } @Override public void createTable(String tableName, Set indexedColumns) { super.createTable(tableName, indexedColumns); if (indexedColumns == null) return; for (String columnName : indexedColumns) { setColumnIndexMode(tableName, columnName, ColumnIndexMode.EQUALITY_INDEXED); } } public void setTablePrimaryKeyName(String tableName, String primaryKeyName) { if ((tableName == null) || (primaryKeyName == null)) throw new NullPointerException(); tablePrimaryKeyMap.put(tableName, primaryKeyName); } protected String getTablePrimaryKeyName(String tableName) { String primaryKeyName = tablePrimaryKeyMap.get(tableName); if (primaryKeyName == null) primaryKeyName = DEFAULT_PRIMARY_KEY_NAME; return primaryKeyName; } protected ColumnIndexMode getColumnIndexMode(String tableName, String columnName) { ColumnIndexMode columnIndexMode = null; Map indexedColumnMap = tableIndexedColumnMap.get(tableName); if (indexedColumnMap != null) columnIndexMode = indexedColumnMap.get(columnName); if (columnIndexMode == null) return ColumnIndexMode.NOT_INDEXED; return columnIndexMode; } public void setColumnIndexMode(String tableName, String columnName, ColumnIndexMode indexMode) { Map indexedColumnMap = tableIndexedColumnMap.get(tableName); if (indexedColumnMap == null) { indexedColumnMap = new HashMap(); tableIndexedColumnMap.put(tableName, indexedColumnMap); } indexedColumnMap.put(columnName, indexMode); } Comparable getOperatorPredicateValue(OperatorPredicate predicate, Map> parameterMap) { Comparable value = predicate.getValue(); if (value instanceof String) { String stringValue = (String) value; if ((stringValue.charAt(0) == '?') && (stringValue.charAt(stringValue.length()-1) == '?')) { String parameterName = stringValue.substring(1,stringValue.length()-1); value = parameterMap.get(parameterName); } } return value; } NoSqlPredicate convertPredicate(IPredicate predicate, String tableName, Map> parameterMap) { if (predicate == null) return null; NoSqlPredicate convertedPredicate = null; if (predicate instanceof CompoundPredicate) { CompoundPredicate compoundPredicate = (CompoundPredicate)predicate; ArrayList noSqlPredicateList = new ArrayList(); for (IPredicate childPredicate: compoundPredicate.getPredicateList()) { boolean incorporated = false; if (childPredicate instanceof OperatorPredicate) { OperatorPredicate childOperatorPredicate = (OperatorPredicate)childPredicate; for (NoSqlPredicate childNoSqlPredicate: noSqlPredicateList) { incorporated = childNoSqlPredicate.incorporateComparison( childOperatorPredicate.getColumnName(), childOperatorPredicate.getOperator(), getOperatorPredicateValue(childOperatorPredicate, parameterMap), compoundPredicate.getOperator()); if (incorporated) break; } } if (!incorporated) { NoSqlPredicate noSqlPredicate = convertPredicate(childPredicate, tableName, parameterMap); noSqlPredicateList.add(noSqlPredicate); } } convertedPredicate = new NoSqlCompoundPredicate(this, compoundPredicate.getOperator(), compoundPredicate.isNegated(), noSqlPredicateList); } else if (predicate instanceof OperatorPredicate) { OperatorPredicate operatorPredicate = (OperatorPredicate) predicate; Comparable value = getOperatorPredicateValue(operatorPredicate, parameterMap); switch (operatorPredicate.getOperator()) { case EQ: convertedPredicate = new NoSqlRangePredicate(this, tableName, operatorPredicate.getColumnName(), value, true, value, true); break; case LT: convertedPredicate = new NoSqlRangePredicate(this, tableName, operatorPredicate.getColumnName(), null, false, value, false); break; case LTE: convertedPredicate = new NoSqlRangePredicate(this, tableName, operatorPredicate.getColumnName(), null, false, value, true); break; case GT: convertedPredicate = new NoSqlRangePredicate(this, tableName, operatorPredicate.getColumnName(), value, false, null, false); break; case GTE: convertedPredicate = new NoSqlRangePredicate(this, tableName, operatorPredicate.getColumnName(), value, true, null, false); break; default: convertedPredicate = new NoSqlOperatorPredicate(this, operatorPredicate.getColumnName(), operatorPredicate.getOperator(), value); } } else { throw new StorageException("Unknown predicate type"); } return convertedPredicate; } @SuppressWarnings({ "unchecked", "rawtypes" }) class RowComparator implements Comparator> { private RowOrdering rowOrdering; public RowComparator(RowOrdering rowOrdering) { this.rowOrdering = rowOrdering; } public int compare(Map row1, Map row2) { if (rowOrdering == null) return 0; for (RowOrdering.Item item: rowOrdering.getItemList()) { Comparable key1 = (Comparable)row1.get(item.getColumn()); Comparable key2 = (Comparable)row2.get(item.getColumn()); int result = key1.compareTo(key2); if (result != 0) { if (item.getDirection() == RowOrdering.Direction.DESCENDING) result = -result; return result; } } return 0; } public boolean equals(Object obj) { if (!(obj instanceof RowComparator)) return false; RowComparator rc = (RowComparator)obj; if (rc.rowOrdering == null) return this.rowOrdering == null; return rc.rowOrdering.equals(this.rowOrdering); } } private NoSqlResultSet executeParameterizedQuery(String tableName, String[] columnNameList, IPredicate predicate, RowOrdering rowOrdering, Map> parameterMap) { NoSqlPredicate noSqlPredicate = convertPredicate(predicate, tableName, parameterMap); List> rowList; if ((noSqlPredicate != null) && noSqlPredicate.canExecuteEfficiently()) { rowList = noSqlPredicate.execute(columnNameList); } else { rowList = new ArrayList>(); Collection> allRowList = getAllRows(tableName, columnNameList); for (Map row: allRowList) { if ((noSqlPredicate == null) || noSqlPredicate.matchesRow(row)) { rowList.add(row); } } } if (rowOrdering != null) Collections.sort(rowList, new RowComparator(rowOrdering)); return new NoSqlResultSet(this, tableName, rowList); } @Override public IQuery createQuery(String tableName, String[] columnNameList, IPredicate predicate, RowOrdering rowOrdering) { return new NoSqlQuery(tableName, columnNameList, predicate, rowOrdering); } @Override public IResultSet executeQueryImpl(IQuery query) { NoSqlQuery noSqlQuery = (NoSqlQuery) query; return executeParameterizedQuery(noSqlQuery.getTableName(), noSqlQuery.getColumnNameList(), noSqlQuery.getPredicate(), noSqlQuery.getRowOrdering(), noSqlQuery.getParameterMap()); } protected void sendNotification(String tableName, StorageSourceNotification.Action action, List> rows) { Set rowKeys = new HashSet(); String primaryKeyName = getTablePrimaryKeyName(tableName); for (Map row : rows) { Object rowKey = row.get(primaryKeyName); rowKeys.add(rowKey); } StorageSourceNotification notification = new StorageSourceNotification(tableName, action, rowKeys); notifyListeners(notification); } protected void sendNotification(String tableName, StorageSourceNotification.Action action, Set rowKeys) { StorageSourceNotification notification = new StorageSourceNotification(tableName, action, rowKeys); notifyListeners(notification); } protected void insertRowsAndNotify(String tableName, List> insertRowList) { insertRows(tableName, insertRowList); sendNotification(tableName, StorageSourceNotification.Action.MODIFY, insertRowList); } @Override public void insertRowImpl(String tableName, Map values) { ArrayList> rowList = new ArrayList>(); rowList.add(values); insertRowsAndNotify(tableName, rowList); } protected void updateRowsAndNotify(String tableName, Set rowKeys, Map updateRowList) { updateRows(tableName, rowKeys, updateRowList); sendNotification(tableName, StorageSourceNotification.Action.MODIFY, rowKeys); } protected void updateRowsAndNotify(String tableName, List> updateRowList) { updateRows(tableName, updateRowList); sendNotification(tableName, StorageSourceNotification.Action.MODIFY, updateRowList); } @Override public void updateMatchingRowsImpl(String tableName, IPredicate predicate, Map values) { String primaryKeyName = getTablePrimaryKeyName(tableName); String[] columnNameList = {primaryKeyName}; IResultSet resultSet = executeQuery(tableName, columnNameList, predicate, null); Set rowKeys = new HashSet(); while (resultSet.next()) { String rowKey = resultSet.getString(primaryKeyName); rowKeys.add(rowKey); } updateRowsAndNotify(tableName, rowKeys, values); } @Override public void updateRowImpl(String tableName, Object rowKey, Map values) { Map valuesWithKey = new HashMap(values); String primaryKeyName = getTablePrimaryKeyName(tableName); valuesWithKey.put(primaryKeyName, rowKey); List> rowList = new ArrayList>(); rowList.add(valuesWithKey); updateRowsAndNotify(tableName, rowList); } @Override public void updateRowImpl(String tableName, Map values) { List> rowKeys = new ArrayList>(); rowKeys.add(values); updateRowsAndNotify(tableName, rowKeys); } protected void deleteRowsAndNotify(String tableName, Set rowKeyList) { deleteRows(tableName, rowKeyList); sendNotification(tableName, StorageSourceNotification.Action.DELETE, rowKeyList); } @Override public void deleteRowImpl(String tableName, Object key) { HashSet keys = new HashSet(); keys.add(key); deleteRowsAndNotify(tableName, keys); } @Override public IResultSet getRowImpl(String tableName, Object rowKey) { List> rowList = new ArrayList>(); Map row = getRow(tableName, null, rowKey); if (row != null) rowList.add(row); NoSqlResultSet resultSet = new NoSqlResultSet(this, tableName, rowList); return resultSet; } // Below are the methods that must be implemented by the subclasses protected abstract Collection> getAllRows(String tableName, String[] columnNameList); protected abstract Map getRow(String tableName, String[] columnNameList, Object rowKey); protected abstract List> executeEqualityQuery(String tableName, String[] columnNameList, String predicateColumnName, Comparable value); protected abstract List> executeRangeQuery(String tableName, String[] columnNameList, String predicateColumnName, Comparable startValue, boolean startInclusive, Comparable endValue, boolean endInclusive); protected abstract void insertRows(String tableName, List> insertRowList); protected abstract void updateRows(String tableName, Set rowKeys, Map updateColumnMap); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/NullValueStorageException.java0000664000175000017500000000277712041336206033366 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; public class NullValueStorageException extends StorageException { private static final long serialVersionUID = 897572085681189926L; private static String makeExceptionMessage(String columnName) { String message = "Null column value could not be converted to built-in type"; if (columnName != null) { message += ": column name = "; message += columnName; } return message; } public NullValueStorageException() { super(makeExceptionMessage(null)); } public NullValueStorageException(String columnName) { super(makeExceptionMessage(columnName)); } public NullValueStorageException(String columnName, Throwable exc) { super(makeExceptionMessage(columnName), exc); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IQuery.java0000664000175000017500000000306512041336206027460 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; /** Representation of a database query. For SQL queries this maps to * a prepared statement, so it will be more efficient than if you use the * methods in IStorageSource that bypass the IQuery. For many NoSQL * storage sources there won't be any performance improvement from keeping * around the query. * * The query interface also supports parameterized queries (i.e. which maps * to using ? values in a SQL query). The values of the parameters are set * using the setParameter method. In the storage source API the parameters * are named rather than positional. The format of the parameterized values * in the query predicates is the parameter name bracketed with question marks * (e.g. ?MinimumSalary? ). * * @author rob * */ public interface IQuery { String getTableName(); void setParameter(String name, Object value); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/memory/0000775000175000017500000000000012041336206026703 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/storage/memory/MemoryTable.java0000664000175000017500000000404112041336206031765 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.memory; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; public class MemoryTable { private String tableName; private Map> rowMap; private int nextId; MemoryTable(String tableName) { this.tableName = tableName; rowMap = new TreeMap>(); nextId = 0; } String getTableName() { return tableName; } Collection> getAllRows() { return rowMap.values(); } Map getRow(Object key) { Map row = rowMap.get(key); return row; } // rkv: Do we still need this? Probably needs to be tweaked a bit // to work with the support for specifying which column to use as the // primary key Map newRow(Object key) { Map row = new HashMap(); row.put("id", key); rowMap.put(key, row); return row; } void insertRow(Object key, Map rowValues) { assert(key != null); rowMap.put(key, rowValues); } void deleteRow(Object rowKey) { rowMap.remove(rowKey); } Integer getNextId() { return new Integer(++nextId); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/memory/MemoryStorageSource.java0000664000175000017500000001716212041336206033533 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.memory; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.storage.nosql.NoSqlStorageSource; import net.floodlightcontroller.storage.SynchronousExecutorService; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.core.module.IFloodlightService; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import net.floodlightcontroller.storage.StorageException; public class MemoryStorageSource extends NoSqlStorageSource { private Map tableMap = new HashMap(); IPktInProcessingTimeService pktinProcessingTime; synchronized private MemoryTable getTable(String tableName, boolean create) { MemoryTable table = tableMap.get(tableName); if (table == null) { if (!create) throw new StorageException("Table " + tableName + " does not exist"); table = new MemoryTable(tableName); tableMap.put(tableName, table); } return table; } @Override protected Collection> getAllRows(String tableName, String[] columnNameList) { MemoryTable table = getTable(tableName, false); return table.getAllRows(); } @Override protected Map getRow(String tableName, String[] columnNameList, Object rowKey) { MemoryTable table = getTable(tableName, false); return table.getRow(rowKey); } @Override protected List> executeEqualityQuery(String tableName, String[] columnNameList, String predicateColumnName, Comparable value) { MemoryTable table = getTable(tableName, false); List> result = new ArrayList>(); synchronized (table) { Collection> allRows = table.getAllRows(); for (Map row : allRows) { Object v = row.get(predicateColumnName); if (value.equals(v)) { result.add(row); } } } return result; } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected List> executeRangeQuery(String tableName, String[] columnNameList, String predicateColumnName, Comparable startValue, boolean startInclusive, Comparable endValue, boolean endInclusive) { MemoryTable table = getTable(tableName, false); List> result = new ArrayList>(); synchronized (table) { Collection> allRows = table.getAllRows(); for (Map row : allRows) { Comparable value = (Comparable) row.get(predicateColumnName); if (value != null) { int compareResult = value.compareTo(startValue); if ((compareResult > 0) || (startInclusive && (compareResult >= 0))) { compareResult = value.compareTo(endValue); if ((compareResult < 0) || (startInclusive && (compareResult <= 0))) { result.add(row); } } } } } return result; } @Override protected void insertRows(String tableName, List> insertRowList) { MemoryTable table = getTable(tableName, false); String primaryKeyName = getTablePrimaryKeyName(tableName); synchronized (table) { for (Map row : insertRowList) { Object primaryKey = row.get(primaryKeyName); if (primaryKey == null) { if (primaryKeyName.equals(DEFAULT_PRIMARY_KEY_NAME)) { row = new HashMap(row); primaryKey = table.getNextId(); row.put(primaryKeyName, primaryKey); } } table.insertRow(primaryKey, row); } } } @Override protected void updateRows(String tableName, Set rowKeys, Map updateRowList) { MemoryTable table = getTable(tableName, false); synchronized (table) { for (Object rowKey : rowKeys) { Map row = table.getRow(rowKey); if (row == null) row = table.newRow(rowKey); for (Map.Entry entry: updateRowList.entrySet()) { row.put(entry.getKey(), entry.getValue()); } } } } @Override protected void updateRowsImpl(String tableName, List> updateRowList) { MemoryTable table = getTable(tableName, false); String primaryKeyName = getTablePrimaryKeyName(tableName); synchronized (table) { for (Map updateRow : updateRowList) { Object rowKey = updateRow.get(primaryKeyName); if (rowKey == null) throw new StorageException("Primary key not found."); Map row = table.getRow(rowKey); if (row == null) row = table.newRow(rowKey); for (Map.Entry entry: updateRow.entrySet()) { row.put(entry.getKey(), entry.getValue()); } } } } @Override protected void deleteRowsImpl(String tableName, Set rowKeys) { MemoryTable table = getTable(tableName, false); synchronized (table) { for (Object rowKey : rowKeys) { table.deleteRow(rowKey); } } } @Override public void createTable(String tableName, Set indexedColumnNames) { super.createTable(tableName, indexedColumnNames); getTable(tableName, true); } public void setPktinProcessingTime( IPktInProcessingTimeService pktinProcessingTime) { this.pktinProcessingTime = pktinProcessingTime; } // IFloodlightModule methods @Override public void startUp(FloodlightModuleContext context) { super.startUp(context); executorService = new SynchronousExecutorService(); } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IStorageSourceService.class, this); return m; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IPredicate.java0000664000175000017500000000172612041336206030255 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; /** Common base interface for the OperatorPredicate and CompoundPredicate classes. * It's necessary so that you can use either type of predicate as child * predicates of a CompoundPredicate. * @author rob */ public interface IPredicate { } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/StorageException.java0000664000175000017500000000253712041336206031530 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; public class StorageException extends RuntimeException { static final long serialVersionUID = 7839989010156155681L; static private String makeExceptionMessage(String s) { String message = "Storage Exception"; if (s != null) { message += ": "; message += s; } return message; } public StorageException() { super(makeExceptionMessage(null)); } public StorageException(String s) { super(makeExceptionMessage(s)); } public StorageException(String s, Throwable exc) { super(makeExceptionMessage(s), exc); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/TypeMismatchStorageException.java0000664000175000017500000000323212041336206034051 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; public class TypeMismatchStorageException extends StorageException { private static final long serialVersionUID = -7923586656854871345L; private static String makeExceptionMessage(String requestedType, String actualType, String columnName) { if (requestedType == null) requestedType = "???"; if (actualType == null) actualType = "???"; if (columnName == null) columnName = "???"; String message = "The requested type (" + requestedType + ") does not match the actual type (" + actualType + ") of the value for column \"" + columnName + "\"."; return message; } public TypeMismatchStorageException() { super(makeExceptionMessage(null, null, null)); } public TypeMismatchStorageException(String requestedType, String actualType, String columnName) { super(makeExceptionMessage(requestedType, actualType, columnName)); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java0000664000175000017500000004655212041336206032523 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.ICounter; import net.floodlightcontroller.counter.CounterStore; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.counter.CounterValue.CounterType; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.web.StorageWebRoutable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @LogMessageCategory("System Database") public abstract class AbstractStorageSource implements IStorageSourceService, IFloodlightModule { protected static Logger logger = LoggerFactory.getLogger(AbstractStorageSource.class); // Shared instance of the executor to use to execute the storage tasks. // We make this a single threaded executor, because if we used a thread pool // then storage operations could be executed out of order which would cause // problems in some cases (e.g. delete and update of a row getting reordered). // If we wanted to make this more multi-threaded we could have multiple // worker threads/executors with affinity of operations on a given table // to a single worker thread. But for now, we'll keep it simple and just have // a single thread for all operations. protected static ExecutorService defaultExecutorService = Executors.newSingleThreadExecutor(); protected final static String STORAGE_QUERY_COUNTER_NAME = "StorageQuery"; protected final static String STORAGE_UPDATE_COUNTER_NAME = "StorageUpdate"; protected final static String STORAGE_DELETE_COUNTER_NAME = "StorageDelete"; protected Set allTableNames = new CopyOnWriteArraySet(); protected ICounterStoreService counterStore; protected ExecutorService executorService = defaultExecutorService; protected IStorageExceptionHandler exceptionHandler; private Map> listeners = new ConcurrentHashMap>(); // Our dependencies protected IRestApiService restApi = null; protected static final String DB_ERROR_EXPLANATION = "An unknown error occurred while executing asynchronous " + "database operation"; @LogMessageDoc(level="ERROR", message="Failure in asynchronous call to executeQuery", explanation=DB_ERROR_EXPLANATION, recommendation=LogMessageDoc.GENERIC_ACTION) abstract class StorageCallable implements Callable { public V call() { try { return doStorageOperation(); } catch (StorageException e) { logger.error("Failure in asynchronous call to executeQuery", e); if (exceptionHandler != null) exceptionHandler.handleException(e); throw e; } } abstract protected V doStorageOperation(); } @LogMessageDoc(level="ERROR", message="Failure in asynchronous call to updateRows", explanation=DB_ERROR_EXPLANATION, recommendation=LogMessageDoc.GENERIC_ACTION) abstract class StorageRunnable implements Runnable { public void run() { try { doStorageOperation(); } catch (StorageException e) { logger.error("Failure in asynchronous call to updateRows", e); if (exceptionHandler != null) exceptionHandler.handleException(e); throw e; } } abstract void doStorageOperation(); } public AbstractStorageSource() { this.executorService = defaultExecutorService; } public void setExecutorService(ExecutorService executorService) { this.executorService = (executorService != null) ? executorService : defaultExecutorService; } @Override public void setExceptionHandler(IStorageExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; } @Override public abstract void setTablePrimaryKeyName(String tableName, String primaryKeyName); @Override public void createTable(String tableName, Set indexedColumns) { allTableNames.add(tableName); } @Override public Set getAllTableNames() { return allTableNames; } public void setCounterStore(CounterStore counterStore) { this.counterStore = counterStore; } protected void updateCounters(String baseName, String tableName) { if (counterStore != null) { String counterName; if (tableName != null) { updateCounters(baseName, null); counterName = baseName + CounterStore.TitleDelimitor + tableName; } else { counterName = baseName; } ICounter counter = counterStore.getCounter(counterName); if (counter == null) { counter = counterStore.createCounter(counterName, CounterType.LONG); } counter.increment(); } } @Override public abstract IQuery createQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering); @Override public IResultSet executeQuery(IQuery query) { updateCounters(STORAGE_QUERY_COUNTER_NAME, query.getTableName()); return executeQueryImpl(query); } protected abstract IResultSet executeQueryImpl(IQuery query); @Override public IResultSet executeQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering) { IQuery query = createQuery(tableName, columnNames, predicate, ordering); IResultSet resultSet = executeQuery(query); return resultSet; } @Override public Object[] executeQuery(String tableName, String[] columnNames, IPredicate predicate, RowOrdering ordering, IRowMapper rowMapper) { List objectList = new ArrayList(); IResultSet resultSet = executeQuery(tableName, columnNames, predicate, ordering); while (resultSet.next()) { Object object = rowMapper.mapRow(resultSet); objectList.add(object); } return objectList.toArray(); } @Override public Future executeQueryAsync(final IQuery query) { Future future = executorService.submit( new StorageCallable() { public IResultSet doStorageOperation() { return executeQuery(query); } }); return future; } @Override public Future executeQueryAsync(final String tableName, final String[] columnNames, final IPredicate predicate, final RowOrdering ordering) { Future future = executorService.submit( new StorageCallable() { public IResultSet doStorageOperation() { return executeQuery(tableName, columnNames, predicate, ordering); } }); return future; } @Override public Future executeQueryAsync(final String tableName, final String[] columnNames, final IPredicate predicate, final RowOrdering ordering, final IRowMapper rowMapper) { Future future = executorService.submit( new StorageCallable() { public Object[] doStorageOperation() { return executeQuery(tableName, columnNames, predicate, ordering, rowMapper); } }); return future; } @Override public Future insertRowAsync(final String tableName, final Map values) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { insertRow(tableName, values); } }, null); return future; } @Override public Future updateRowsAsync(final String tableName, final List> rows) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { updateRows(tableName, rows); } }, null); return future; } @Override public Future updateMatchingRowsAsync(final String tableName, final IPredicate predicate, final Map values) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { updateMatchingRows(tableName, predicate, values); } }, null); return future; } @Override public Future updateRowAsync(final String tableName, final Object rowKey, final Map values) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { updateRow(tableName, rowKey, values); } }, null); return future; } @Override public Future updateRowAsync(final String tableName, final Map values) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { updateRow(tableName, values); } }, null); return future; } @Override public Future deleteRowAsync(final String tableName, final Object rowKey) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { deleteRow(tableName, rowKey); } }, null); return future; } @Override public Future deleteRowsAsync(final String tableName, final Set rowKeys) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { deleteRows(tableName, rowKeys); } }, null); return future; } @Override public Future deleteMatchingRowsAsync(final String tableName, final IPredicate predicate) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { deleteMatchingRows(tableName, predicate); } }, null); return future; } @Override public Future getRowAsync(final String tableName, final Object rowKey) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { getRow(tableName, rowKey); } }, null); return future; } @Override public Future saveAsync(final IResultSet resultSet) { Future future = executorService.submit( new StorageRunnable() { public void doStorageOperation() { resultSet.save(); } }, null); return future; } @Override public void insertRow(String tableName, Map values) { updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName); insertRowImpl(tableName, values); } protected abstract void insertRowImpl(String tableName, Map values); @Override public void updateRows(String tableName, List> rows) { updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName); updateRowsImpl(tableName, rows); } protected abstract void updateRowsImpl(String tableName, List> rows); @Override public void updateMatchingRows(String tableName, IPredicate predicate, Map values) { updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName); updateMatchingRowsImpl(tableName, predicate, values); } protected abstract void updateMatchingRowsImpl(String tableName, IPredicate predicate, Map values); @Override public void updateRow(String tableName, Object rowKey, Map values) { updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName); updateRowImpl(tableName, rowKey, values); } protected abstract void updateRowImpl(String tableName, Object rowKey, Map values); @Override public void updateRow(String tableName, Map values) { updateCounters(STORAGE_UPDATE_COUNTER_NAME, tableName); updateRowImpl(tableName, values); } protected abstract void updateRowImpl(String tableName, Map values); @Override public void deleteRow(String tableName, Object rowKey) { updateCounters(STORAGE_DELETE_COUNTER_NAME, tableName); deleteRowImpl(tableName, rowKey); } protected abstract void deleteRowImpl(String tableName, Object rowKey); @Override public void deleteRows(String tableName, Set rowKeys) { updateCounters(STORAGE_DELETE_COUNTER_NAME, tableName); deleteRowsImpl(tableName, rowKeys); } protected abstract void deleteRowsImpl(String tableName, Set rowKeys); @Override public void deleteMatchingRows(String tableName, IPredicate predicate) { IResultSet resultSet = null; try { resultSet = executeQuery(tableName, null, predicate, null); while (resultSet.next()) { resultSet.deleteRow(); } resultSet.save(); } finally { if (resultSet != null) resultSet.close(); } } @Override public IResultSet getRow(String tableName, Object rowKey) { updateCounters(STORAGE_QUERY_COUNTER_NAME, tableName); return getRowImpl(tableName, rowKey); } protected abstract IResultSet getRowImpl(String tableName, Object rowKey); @Override public synchronized void addListener(String tableName, IStorageSourceListener listener) { Set tableListeners = listeners.get(tableName); if (tableListeners == null) { tableListeners = new CopyOnWriteArraySet(); listeners.put(tableName, tableListeners); } tableListeners.add(listener); } @Override public synchronized void removeListener(String tableName, IStorageSourceListener listener) { Set tableListeners = listeners.get(tableName); if (tableListeners != null) { tableListeners.remove(listener); } } @LogMessageDoc(level="ERROR", message="Exception caught handling storage notification", explanation="An unknown error occured while trying to notify" + " storage listeners", recommendation=LogMessageDoc.GENERIC_ACTION) protected synchronized void notifyListeners(StorageSourceNotification notification) { String tableName = notification.getTableName(); Set keys = notification.getKeys(); Set tableListeners = listeners.get(tableName); if (tableListeners != null) { for (IStorageSourceListener listener : tableListeners) { try { switch (notification.getAction()) { case MODIFY: listener.rowsModified(tableName, keys); break; case DELETE: listener.rowsDeleted(tableName, keys); break; } } catch (Exception e) { logger.error("Exception caught handling storage notification", e); } } } } @Override public void notifyListeners(List notifications) { for (StorageSourceNotification notification : notifications) notifyListeners(notification); } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IStorageSourceService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IStorageSourceService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IRestApiService.class); l.add(ICounterStoreService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { restApi = context.getServiceImpl(IRestApiService.class); counterStore = context.getServiceImpl(ICounterStoreService.class); } @Override public void startUp(FloodlightModuleContext context) { restApi.addRestletRoutable(new StorageWebRoutable()); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/StorageSourceNotification.java0000664000175000017500000000601012041336206033367 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.Set; public class StorageSourceNotification { public enum Action { MODIFY, DELETE }; private String tableName; private Action action; private Set keys; public StorageSourceNotification() { } public StorageSourceNotification(String tableName, Action action, Set keys) { this.tableName = tableName; this.action = action; this.keys = keys; } public String getTableName() { return tableName; } public Action getAction() { return action; } public Set getKeys() { return keys; } public void setTableName(String tableName) { this.tableName = tableName; } public void setAction(Action action) { this.action = action; } public void setKeys(Set keys) { this.keys = keys; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 7867; int result = 1; result = prime * result + tableName.hashCode(); result = prime * result + action.hashCode(); result = prime * result + keys.hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof StorageSourceNotification)) return false; StorageSourceNotification other = (StorageSourceNotification) obj; if (tableName == null) { if (other.tableName != null) return false; } else if (!tableName.equals(other.tableName)) return false; if (action == null) { if (other.action != null) return false; } else if (action != other.action) return false; if (keys == null) { if (other.keys != null) return false; } else if (!keys.equals(other.keys)) return false; return true; } @Override public String toString() { return ("StorageNotification[table=" + tableName + "; action=" + action.toString() + "; keys=" + keys.toString() + "]"); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IStorageSourceListener.java0000664000175000017500000000252212041336206032643 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.Set; public interface IStorageSourceListener { /** * Called when rows are inserted or updated in the table. * * @param tableName The table where the rows were inserted * @param rowKeys The keys of the rows that were inserted */ public void rowsModified(String tableName, Set rowKeys); /** * Called when a new row is deleted from the table. * * @param tableName The table where the rows were deleted * @param rowKeys The keys of the rows that were deleted */ public void rowsDeleted(String tableName, Set rowKeys); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IRowMapper.java0000664000175000017500000000234412041336206030266 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; /** * Interface for mapping the current row in a result set to an object. * This is based on the Spring JDBC support. * * @author rob */ public interface IRowMapper { /** This method must be implemented by the client of the storage API * to map the current row in the result set to a Java object. * * @param resultSet The result set obtained from a storage source query * @return The object created from the data in the result set */ Object mapRow(IResultSet resultSet); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/web/0000775000175000017500000000000012041336206026150 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/storage/web/StorageNotifyResource.java0000664000175000017500000000401612041336206033321 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.web; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.StorageSourceNotification; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.restlet.resource.Post; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StorageNotifyResource extends ServerResource { protected static Logger log = LoggerFactory.getLogger(StorageNotifyResource.class); @Post("json") public Map notify(String entity) throws Exception { List notifications = null; ObjectMapper mapper = new ObjectMapper(); notifications = mapper.readValue(entity, new TypeReference>(){}); IStorageSourceService storageSource = (IStorageSourceService)getContext().getAttributes(). get(IStorageSourceService.class.getCanonicalName()); storageSource.notifyListeners(notifications); HashMap model = new HashMap(); model.put("output", "OK"); return model; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/web/StorageWebRoutable.java0000664000175000017500000000246012041336206032555 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.web; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import net.floodlightcontroller.restserver.RestletRoutable; /** * Creates a router to handle the storage web URIs * @author readams * */ public class StorageWebRoutable implements RestletRoutable { @Override public String basePath() { return "/wm/storage"; } @Override public Restlet getRestlet(Context context) { Router router = new Router(context); router.attach("/notify/json", StorageNotifyResource.class); return router; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IResultSet.java0000664000175000017500000001034012041336206030277 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.Date; import java.util.Map; /** Interface to iterate over the results from a storage query. * * @author rob * */ public interface IResultSet extends Iterable { /** This should be called when the client is done using the result set. * This will release any underlying resources (e.g. a database connection), * which you don't want to wait for or rely on finalizers to release. */ public void close(); /** Advance to the next row in the result set. * @return Returns true if there are more rows to process * (i.e. if there's a valid current row) and false if there are no more * rows in the result set. */ public boolean next(); /** Save/commit any pending updates to the data in the result set. * This must be called after any calls to the set methods or deleting rows * for the changes to be applied/committed to the storage source. Note that * this doesn't need to be called after each set method or even after each * row. It is typically called at the end after updating all of the * rows in the result set. */ public void save(); /** Get the current row in the result set. This returns all of the * columns in the current row. * @return Map containing all of the columns in the current row, indexed * by the column name. */ public Map getRow(); /** Delete the current row in the result set. */ public void deleteRow(); public boolean containsColumn(String columnName); public String getString(String columnName); public short getShort(String columnName); public int getInt(String columnName); public long getLong(String columnName); public float getFloat(String columnName); public double getDouble(String columnName); public boolean getBoolean(String columnName); public byte getByte(String columnName); public byte[] getByteArray(String columnName); public Date getDate(String columnName); public Short getShortObject(String columnName); public Integer getIntegerObject(String columnName); public Long getLongObject(String columnName); public Float getFloatObject(String columnName); public Double getDoubleObject(String columnName); public Boolean getBooleanObject(String columnName); public Byte getByteObject(String columnName); public boolean isNull(String columnName); public void setString(String columnName, String value); public void setShort(String columnName, short value); public void setInt(String columnName, int value); public void setLong(String columnName, long value); public void setFloat(String columnName, float value); public void setDouble(String columnName, double value); public void setBoolean(String columnName, boolean value); public void setByte(String columnName, byte value); public void setByteArray(String columnName, byte[] byteArray); public void setDate(String columnName, Date date); public void setShortObject(String columnName, Short value); public void setIntegerObject(String columnName, Integer value); public void setLongObject(String columnName, Long value); public void setFloatObject(String columnName, Float value); public void setDoubleObject(String columnName, Double value); public void setBooleanObject(String columnName, Boolean value); public void setByteObject(String columnName, Byte value); public void setNull(String columnName); } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/CompoundPredicate.java0000664000175000017500000000311312041336206031641 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; /** Predicate class to handle AND and OR combinations of a number * of child predicates. The result of the logical combination of the * child predicates can also be negated to support a NOT operation. * * @author rob * */ public class CompoundPredicate implements IPredicate { public enum Operator { AND, OR }; private Operator operator; private boolean negated; private IPredicate[] predicateList; public CompoundPredicate(Operator operator, boolean negated, IPredicate... predicateList) { this.operator = operator; this.negated = negated; this.predicateList = predicateList; } public Operator getOperator() { return operator; } public boolean isNegated() { return negated; } public IPredicate[] getPredicateList() { return predicateList; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/OperatorPredicate.java0000664000175000017500000000306512041336206031656 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; /** Predicate class to specify rows by equality or comparison operations * of column values. The Storage API uses the special column name of "id" * to specify the primary key values for the row. * * @author rob */ public class OperatorPredicate implements IPredicate { public enum Operator { EQ, LT, LTE, GT, GTE }; private String columnName; private Operator operator; private Comparable value; public OperatorPredicate(String columnName, Operator operator, Comparable value) { this.columnName = columnName; this.operator = operator; this.value = value; } public String getColumnName() { return columnName; } public Operator getOperator() { return operator; } public Comparable getValue() { return value; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/RowOrdering.java0000664000175000017500000000610512041336206030501 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.ArrayList; import java.util.List; public class RowOrdering { public enum Direction { ASCENDING, DESCENDING }; public class Item { private String column; private Direction direction; public Item(String column, Direction direction) { assert(column != null); assert(direction != null); this.column = column; this.direction = direction; } public String getColumn() { return column; } public Direction getDirection() { return direction; } } private List itemList = new ArrayList(); public RowOrdering() { } public RowOrdering(String column) { add(column); } public RowOrdering(String column, Direction direction) { add(column, direction); } public RowOrdering(Item item) { add(item); } public RowOrdering(Item[] itemArray) { add(itemArray); } public RowOrdering(List itemList) { add(itemList); } public void add(String column) { itemList.add(new Item(column, Direction.ASCENDING)); } public void add(String column, Direction direction) { itemList.add(new Item(column, direction)); } public void add(Item item) { assert(item != null); itemList.add(item); } public void add(Item[] itemArray) { for (Item item: itemArray) { itemList.add(item); } } public void add(List itemList) { this.itemList.addAll(itemList); } public List getItemList() { return itemList; } public boolean equals(RowOrdering rowOrdering) { if (rowOrdering == null) return false; int len1 = itemList.size(); int len2 = rowOrdering.getItemList().size(); if (len1 != len2) return false; for (int i = 0; i < len1; i++) { Item item1 = itemList.get(i); Item item2 = rowOrdering.getItemList().get(i); if (!item1.getColumn().equals(item2.getColumn()) || item1.getDirection() != item2.getDirection()) return false; } return true; } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/IStorageExceptionHandler.java0000664000175000017500000000150012041336206033124 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; public interface IStorageExceptionHandler { public void handleException(Exception exc); } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/storage/StorageNotificationFormatException.javafloodlight-0.90/src/main/java/net/floodlightcontroller/storage/StorageNotificationFormatException.ja0000664000175000017500000000174412041336206034720 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; public class StorageNotificationFormatException extends StorageException { private static final long serialVersionUID = 504758477518283156L; public StorageNotificationFormatException() { super("Invalid storage notification format"); } } floodlight-0.90/src/main/java/net/floodlightcontroller/storage/SynchronousExecutorService.java0000664000175000017500000001124512041336206033633 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class SynchronousExecutorService implements ExecutorService { class SynchronousFuture implements Future { T result; Exception exc; public SynchronousFuture() { } public SynchronousFuture(T result) { this.result = result; } public SynchronousFuture(Exception exc) { this.exc = exc; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return true; } @Override public T get() throws InterruptedException, ExecutionException { if (exc != null) throw new ExecutionException(exc); return result; } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return get(); } } @Override public void shutdown() { } @Override public List shutdownNow() { return null; } @Override public boolean isShutdown() { return false; } @Override public boolean isTerminated() { return false; } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return false; } @Override public List> invokeAll(Collection> tasks) throws InterruptedException { List> l = new ArrayList>(); for (Callable task : tasks) { Future future = submit(task); l.add(future); } return l; } @Override public List> invokeAll( Collection> tasks, long timeout, TimeUnit units) throws InterruptedException { return invokeAll(tasks); } @Override public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { for (Callable task : tasks) { try { task.call(); } catch (Exception e) { } } throw new ExecutionException(new Exception("no task completed successfully")); } @Override public T invokeAny(Collection> tasks, long timeout, TimeUnit units) throws InterruptedException, ExecutionException, TimeoutException { return invokeAny(tasks); } @Override public Future submit(Callable callable) { try { T result = callable.call(); return new SynchronousFuture(result); } catch (Exception exc) { return new SynchronousFuture(exc); } } @Override public Future submit(Runnable runnable) { try { runnable.run(); return new SynchronousFuture(); } catch (Exception exc) { return new SynchronousFuture(exc); } } @Override public Future submit(Runnable runnable, T result) { try { runnable.run(); return new SynchronousFuture(result); } catch (Exception exc) { return new SynchronousFuture(exc); } } @Override public void execute(Runnable command) { command.run(); } } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/0000775000175000017500000000000012041336206026614 5ustar jamespagejamespagefloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java0000664000175000017500000000502412041336206033677 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.linkdiscovery; import java.util.Map; import java.util.Set; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.topology.NodePortTuple; public interface ILinkDiscoveryService extends IFloodlightService { /** * Retrieves a map of all known link connections between OpenFlow switches * and the associated info (valid time, port states) for the link. */ public Map getLinks(); /** * Returns link type of a given link * @param info * @return */ public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info); /** * Returns an unmodifiable map from switch id to a set of all links with it * as an endpoint. */ public Map> getSwitchLinks(); /** * Adds a listener to listen for ILinkDiscoveryService messages * @param listener The listener that wants the notifications */ public void addListener(ILinkDiscoveryListener listener); /** * Retrieves a set of all switch ports on which lldps are suppressed. */ public Set getSuppressLLDPsInfo(); /** * Adds a switch port to suppress lldp set */ public void AddToSuppressLLDPs(long sw, short port); /** * Removes a switch port from suppress lldp set */ public void RemoveFromSuppressLLDPs(long sw, short port); /** * Get the set of quarantined ports on a switch */ public Set getQuarantinedPorts(long sw); /** * Get the status of auto port fast feature. */ public boolean isAutoPortFastFeature(); /** * Set the state for auto port fast feature. * @param autoPortFastFeature */ public void setAutoPortFastFeature(boolean autoPortFastFeature); } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/0000775000175000017500000000000012041336206030430 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologyLink.javafloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologyLi0000664000175000017500000000324212041336206035041 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.internal; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; /*** * Topology link up/down event history related classes and members * @author subrata * */ public class EventHistoryTopologyLink { // The following fields are not stored as String to save memory // They should be converted to appropriate human-readable strings by // the front end (e.g. in cli in Python) public long srcSwDpid; public long dstSwDpid; public int srcPortState; public int dstPortState; public int srcSwport; public int dstSwport; public String linkType; public String reason; @JsonProperty("Source-Switch") @JsonSerialize(using=DPIDSerializer.class) public long getSrcSwDpid() { return srcSwDpid; } @JsonProperty("Dest-Switch") @JsonSerialize(using=DPIDSerializer.class) public long getDstSwDpid() { return dstSwDpid; } @JsonProperty("SrcPortState") public int getSrcPortState() { return srcPortState; } @JsonProperty("DstPortState") public int getDstPortState() { return dstPortState; } @JsonProperty("SrcPort") public int getSrcSwport() { return srcSwport; } @JsonProperty("DstPort") public int getDstSwport() { return dstSwport; } @JsonProperty("LinkType") public String getLinkType() { return linkType; } @JsonProperty("Reason") public String getReason() { return reason; } } ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologyCluster.javafloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologyCl0000664000175000017500000000237712041336206035043 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.internal; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; /*** * Topology Cluster merge/split event history related classes and members * @author subrata * */ public class EventHistoryTopologyCluster { // The following fields are not stored as String to save memory // They should be converted to appropriate human-readable strings by // the front end (e.g. in cli in Python) public long dpid; public long clusterIdOld; // Switch with dpid moved from cluster x to y public long clusterIdNew; public String reason; @JsonProperty("Switch") @JsonSerialize(using=DPIDSerializer.class) public long getDpid() { return dpid; } @JsonProperty("OldClusterId") @JsonSerialize(using=DPIDSerializer.class) public long getClusterIdOld() { return clusterIdOld; } @JsonProperty("NewClusterId") @JsonSerialize(using=DPIDSerializer.class) public long getClusterIdNew() { return clusterIdNew; } @JsonProperty("Reason") public String getReason() { return reason; } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologySwitch.javafloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/EventHistoryTopologySw0000664000175000017500000000224512041336206035070 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.internal; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.core.web.serializers.IPv4Serializer; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; /*** * Topology Switch event history related classes and members * @author subrata * */ public class EventHistoryTopologySwitch { // The following fields are not stored as String to save memory // They should be converted to appropriate human-readable strings by // the front end (e.g. in cli in Python) public long dpid; public int ipv4Addr; public int l4Port; public String reason; @JsonProperty("Switch") @JsonSerialize(using=DPIDSerializer.class) public long getDpid() { return dpid; } @JsonProperty("IpAddr") @JsonSerialize(using=IPv4Serializer.class) public int getIpv4Addr() { return ipv4Addr; } @JsonProperty("Port") public int getL4Port() { return l4Port; } @JsonProperty("Reason") public String getReason() { return reason; } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.javafloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.j0000664000175000017500000024335112041336206034673 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.linkdiscovery.internal; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.annotations.LogMessageCategory; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.SingletonTask; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.SwitchType; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation; import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.LinkInfo; import net.floodlightcontroller.packet.BSN; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.LLDP; import net.floodlightcontroller.packet.LLDPTLV; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.IStorageSourceListener; import net.floodlightcontroller.storage.OperatorPredicate; import net.floodlightcontroller.storage.StorageException; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.NodePortTuple; import net.floodlightcontroller.util.EventHistory; import net.floodlightcontroller.util.EventHistory.EvAction; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFPhysicalPort.OFPortConfig; import org.openflow.protocol.OFPhysicalPort.OFPortState; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFPortStatus; import org.openflow.protocol.OFPortStatus.OFPortReason; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.util.HexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class sends out LLDP messages containing the sending switch's datapath * id as well as the outgoing port number. Received LLrescDP messages that * match a known switch cause a new LinkTuple to be created according to the * invariant rules listed below. This new LinkTuple is also passed to routing * if it exists to trigger updates. * * This class also handles removing links that are associated to switch ports * that go down, and switches that are disconnected. * * Invariants: * -portLinks and switchLinks will not contain empty Sets outside of * critical sections * -portLinks contains LinkTuples where one of the src or dst * SwitchPortTuple matches the map key * -switchLinks contains LinkTuples where one of the src or dst * SwitchPortTuple's id matches the switch id * -Each LinkTuple will be indexed into switchLinks for both * src.id and dst.id, and portLinks for each src and dst * -The updates queue is only added to from within a held write lock */ @LogMessageCategory("Network Topology") public class LinkDiscoveryManager implements IOFMessageListener, IOFSwitchListener, IStorageSourceListener, ILinkDiscoveryService, IFloodlightModule, IInfoProvider, IHAListener { protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class); // Names of table/fields for links in the storage API private static final String LINK_TABLE_NAME = "controller_link"; private static final String LINK_ID = "id"; private static final String LINK_SRC_SWITCH = "src_switch_id"; private static final String LINK_SRC_PORT = "src_port"; private static final String LINK_SRC_PORT_STATE = "src_port_state"; private static final String LINK_DST_SWITCH = "dst_switch_id"; private static final String LINK_DST_PORT = "dst_port"; private static final String LINK_DST_PORT_STATE = "dst_port_state"; private static final String LINK_VALID_TIME = "valid_time"; private static final String LINK_TYPE = "link_type"; private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig"; private static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch"; protected IFloodlightProviderService floodlightProvider; protected IStorageSourceService storageSource; protected IThreadPoolService threadPool; protected IRestApiService restApi; // LLDP and BDDP fields private static final byte[] LLDP_STANDARD_DST_MAC_STRING = HexString.fromHexString("01:80:c2:00:00:0e"); private static final long LINK_LOCAL_MASK = 0xfffffffffff0L; private static final long LINK_LOCAL_VALUE = 0x0180c2000000L; // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version // private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01"; private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff"; // Direction TLVs are used to indicate if the LLDPs were sent // periodically or in response to a recieved LLDP private static final byte TLV_DIRECTION_TYPE = 0x73; private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte private static final byte TLV_DIRECTION_VALUE_FORWARD[] = {0x01}; private static final byte TLV_DIRECTION_VALUE_REVERSE[] = {0x02}; private static final LLDPTLV forwardTLV = new LLDPTLV(). setType((byte)TLV_DIRECTION_TYPE). setLength((short)TLV_DIRECTION_LENGTH). setValue(TLV_DIRECTION_VALUE_FORWARD); private static final LLDPTLV reverseTLV = new LLDPTLV(). setType((byte)TLV_DIRECTION_TYPE). setLength((short)TLV_DIRECTION_LENGTH). setValue(TLV_DIRECTION_VALUE_REVERSE); // Link discovery task details. protected SingletonTask discoveryTask; protected final int DISCOVERY_TASK_INTERVAL = 1; protected final int LINK_TIMEOUT = 35; // timeout as part of LLDP process. protected final int LLDP_TO_ALL_INTERVAL = 15 ; //15 seconds. protected long lldpClock = 0; // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL. // If we want to identify link failures faster, we could decrease this // value to a small number, say 1 or 2 sec. protected final int LLDP_TO_KNOWN_INTERVAL= 20; // LLDP frequency for known links protected LLDPTLV controllerTLV; protected ReentrantReadWriteLock lock; int lldpTimeCount = 0; /** * Flag to indicate if automatic port fast is enabled or not. * Default is set to false -- Initialized in the init method as well. */ boolean autoPortFastFeature = false; /** * Map from link to the most recent time it was verified functioning */ protected Map links; /** * Map from switch id to a set of all links with it as an endpoint */ protected Map> switchLinks; /** * Map from a id:port to the set of links containing it as an endpoint */ protected Map> portLinks; /** * Set of link tuples over which multicast LLDPs are received * and unicast LLDPs are not received. */ protected Map> portBroadcastDomainLinks; protected volatile boolean shuttingDown = false; /* topology aware components are called in the order they were added to the * the array */ protected ArrayList linkDiscoveryAware; protected BlockingQueue updates; protected Thread updatesThread; /** * List of ports through which LLDP/BDDPs are not sent. */ protected Set suppressLinkDiscovery; /** A list of ports that are quarantined for discovering links through * them. Data traffic from these ports are not allowed until the ports * are released from quarantine. */ protected LinkedBlockingQueue quarantineQueue; protected LinkedBlockingQueue maintenanceQueue; /** * Quarantine task */ protected SingletonTask bddpTask; protected final int BDDP_TASK_INTERVAL = 100; // 100 ms. protected final int BDDP_TASK_SIZE = 5; // # of ports per iteration /** * Map of broadcast domain ports and the last time a BDDP was either * sent or received on that port. */ protected Map broadcastDomainPortTimeMap; /** * Get the LLDP sending period in seconds. * @return LLDP sending period in seconds. */ public int getLldpFrequency() { return LLDP_TO_KNOWN_INTERVAL; } /** * Get the LLDP timeout value in seconds * @return LLDP timeout value in seconds */ public int getLldpTimeout() { return LINK_TIMEOUT; } public Map> getPortLinks() { return portLinks; } public Set getSuppressLLDPsInfo() { return suppressLinkDiscovery; } /** * Add a switch port to the suppressed LLDP list. * Remove any known links on the switch port. */ public void AddToSuppressLLDPs(long sw, short port) { NodePortTuple npt = new NodePortTuple(sw, port); this.suppressLinkDiscovery.add(npt); deleteLinksOnPort(npt, "LLDP suppressed."); } /** * Remove a switch port from the suppressed LLDP list. * Discover links on that switchport. */ public void RemoveFromSuppressLLDPs(long sw, short port) { NodePortTuple npt = new NodePortTuple(sw, port); this.suppressLinkDiscovery.remove(npt); discover(npt); } public boolean isShuttingDown() { return shuttingDown; } public boolean isFastPort(long sw, short port) { return false; } public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) { if (info.getUnicastValidTime() != null) { return ILinkDiscovery.LinkType.DIRECT_LINK; } else if (info.getMulticastValidTime() != null) { return ILinkDiscovery.LinkType.MULTIHOP_LINK; } return ILinkDiscovery.LinkType.INVALID_LINK; } @LogMessageDoc(level="ERROR", message="Error in link discovery updates loop", explanation="An unknown error occured while dispatching " + "link update notifications", recommendation=LogMessageDoc.GENERIC_ACTION) private void doUpdatesThread() throws InterruptedException { do { LDUpdate update = updates.take(); if (linkDiscoveryAware != null) { if (log.isTraceEnabled()) { log.trace("Dispatching link discovery update {} {} {} {} {} for {}", new Object[]{update.getOperation(), HexString.toHexString(update.getSrc()), update.getSrcPort(), HexString.toHexString(update.getDst()), update.getDstPort(), linkDiscoveryAware}); } try { for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained lda.linkDiscoveryUpdate(update); } } catch (Exception e) { log.error("Error in link discovery updates loop", e); } } } while (updates.peek() != null); } private boolean isLinkDiscoverySuppressed(long sw, short portNumber) { return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber)); } protected void discoverLinks() { // timeout known links. timeoutLinks(); //increment LLDP clock lldpClock = (lldpClock + 1)% LLDP_TO_ALL_INTERVAL; if (lldpClock == 0) { log.debug("Sending LLDP out on all ports."); discoverOnAllPorts(); } } /** * Quarantine Ports. */ protected class QuarantineWorker implements Runnable { @Override public void run() { try { processBDDPLists(); } catch (Exception e) { log.error("Error in quarantine worker thread", e); } finally { bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS); } } } /** * Add a switch port to the quarantine queue. Schedule the * quarantine task if the quarantine queue was empty before adding * this switch port. * @param npt */ protected void addToQuarantineQueue(NodePortTuple npt) { if (quarantineQueue.contains(npt) == false) quarantineQueue.add(npt); } /** * Remove a switch port from the quarantine queue. */ protected void removeFromQuarantineQueue(NodePortTuple npt) { // Remove all occurrences of the node port tuple from the list. while (quarantineQueue.remove(npt)); } /** * Add a switch port to maintenance queue. * @param npt */ protected void addToMaintenanceQueue(NodePortTuple npt) { // TODO We are not checking if the switch port tuple is already // in the maintenance list or not. This will be an issue for // really large number of switch ports in the network. if (maintenanceQueue.contains(npt) == false) maintenanceQueue.add(npt); } /** * Remove a switch port from maintenance queue. * @param npt */ protected void removeFromMaintenanceQueue(NodePortTuple npt) { // Remove all occurrences of the node port tuple from the queue. while (maintenanceQueue.remove(npt)); } /** * This method processes the quarantine list in bursts. The task is * at most once per BDDP_TASK_INTERVAL. * One each call, BDDP_TASK_SIZE number of switch ports are processed. * Once the BDDP packets are sent out through the switch ports, the ports * are removed from the quarantine list. */ protected void processBDDPLists() { int count = 0; Set nptList = new HashSet(); while(count < BDDP_TASK_SIZE && quarantineQueue.peek() !=null) { NodePortTuple npt; npt = quarantineQueue.remove(); sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false); nptList.add(npt); count++; } count = 0; while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) { NodePortTuple npt; npt = maintenanceQueue.remove(); sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false); count++; } for(NodePortTuple npt:nptList) { generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId()); } } public Set getQuarantinedPorts(long sw) { Set qPorts = new HashSet(); Iterator iter = quarantineQueue.iterator(); while (iter.hasNext()) { NodePortTuple npt = iter.next(); if (npt.getNodeId() == sw) { qPorts.add(npt.getPortId()); } } return qPorts; } private void generateSwitchPortStatusUpdate(long sw, short port) { UpdateOperation operation; IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) return; OFPhysicalPort ofp = iofSwitch.getPort(port); if (ofp == null) return; int srcPortState = ofp.getState(); boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue()); if (portUp) operation = UpdateOperation.PORT_UP; else operation = UpdateOperation.PORT_DOWN; updates.add(new LDUpdate(sw, port, operation)); } /** * Send LLDP on known ports */ protected void discoverOnKnownLinkPorts() { // Copy the port set. Set nptSet = new HashSet(); nptSet.addAll(portLinks.keySet()); // Send LLDP from each of them. for(NodePortTuple npt: nptSet) { discover(npt); } } protected void discover(NodePortTuple npt) { discover(npt.getNodeId(), npt.getPortId()); } protected void discover(long sw, short port) { sendDiscoveryMessage(sw, port, true, false); } /** * Send link discovery message out of a given switch port. * The discovery message may be a standard LLDP or a modified * LLDP, where the dst mac address is set to :ff. * * TODO: The modified LLDP will updated in the future and may * use a different eth-type. * @param sw * @param port * @param isStandard indicates standard or modified LLDP * @param isReverse indicates whether the LLDP was sent as a response */ @LogMessageDoc(level="ERROR", message="Failure sending LLDP out port {port} on switch {switch}", explanation="An I/O error occured while sending LLDP message " + "to the switch.", recommendation=LogMessageDoc.CHECK_SWITCH) protected void sendDiscoveryMessage(long sw, short port, boolean isStandard, boolean isReverse) { IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) { return; } if (port == OFPort.OFPP_LOCAL.getValue()) return; OFPhysicalPort ofpPort = iofSwitch.getPort(port); if (ofpPort == null) { if (log.isTraceEnabled()) { log.trace("Null physical port. sw={}, port={}", sw, port); } return; } if (isLinkDiscoverySuppressed(sw, port)) { /* Dont send LLDPs out of this port as suppressLLDPs set * */ return; } // For fast ports, do not send forward LLDPs or BDDPs. if (!isReverse && autoPortFastFeature && isFastPort(sw, port)) return; if (log.isTraceEnabled()) { log.trace("Sending LLDP packet out of swich: {}, port: {}", sw, port); } // using "nearest customer bridge" MAC address for broadest possible propagation // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011), // in particular the Linux bridge which behaves mostly like a provider bridge byte[] chassisId = new byte[] {4, 0, 0, 0, 0, 0, 0}; // filled in later byte[] portId = new byte[] {2, 0, 0}; // filled in later byte[] ttlValue = new byte[] {0, 0x78}; // OpenFlow OUI - 00-26-E1 byte[] dpidTLVValue = new byte[] {0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127).setLength((short) dpidTLVValue.length).setValue(dpidTLVValue); byte[] dpidArray = new byte[8]; ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray); ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2); Long dpid = sw; dpidBB.putLong(dpid); // set the ethernet source mac to last 6 bytes of dpid System.arraycopy(dpidArray, 2, ofpPort.getHardwareAddress(), 0, 6); // set the chassis id's value to last 6 bytes of dpid System.arraycopy(dpidArray, 2, chassisId, 1, 6); // set the optional tlv to the full dpid System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8); // set the portId to the outgoing port portBB.putShort(port); if (log.isTraceEnabled()) { log.trace("Sending LLDP out of interface: {}/{}", HexString.toHexString(sw), port); } LLDP lldp = new LLDP(); lldp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId)); lldp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId)); lldp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue)); lldp.getOptionalTLVList().add(dpidTLV); // Add the controller identifier to the TLV value. lldp.getOptionalTLVList().add(controllerTLV); if (isReverse) { lldp.getOptionalTLVList().add(reverseTLV); }else { lldp.getOptionalTLVList().add(forwardTLV); } Ethernet ethernet; if (isStandard) { ethernet = new Ethernet() .setSourceMACAddress(ofpPort.getHardwareAddress()) .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING) .setEtherType(Ethernet.TYPE_LLDP); ethernet.setPayload(lldp); } else { BSN bsn = new BSN(BSN.BSN_TYPE_BDDP); bsn.setPayload(lldp); ethernet = new Ethernet() .setSourceMACAddress(ofpPort.getHardwareAddress()) .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING) .setEtherType(Ethernet.TYPE_BSN); ethernet.setPayload(bsn); } // serialize and wrap in a packet out byte[] data = ethernet.serialize(); OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); po.setBufferId(OFPacketOut.BUFFER_ID_NONE); po.setInPort(OFPort.OFPP_NONE); // set actions List actions = new ArrayList(); actions.add(new OFActionOutput(port, (short) 0)); po.setActions(actions); po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); // set data po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + data.length); po.setPacketData(data); // send try { iofSwitch.write(po, null); iofSwitch.flush(); } catch (IOException e) { log.error("Failure sending LLDP out port {} on switch {}", new Object[]{ port, iofSwitch.getStringId() }, e); } } /** * Send LLDPs to all switch-ports */ protected void discoverOnAllPorts() { if (log.isTraceEnabled()) { log.trace("Sending LLDP packets out of all the enabled ports on switch {}"); } Set switches = floodlightProvider.getSwitches().keySet(); // Send standard LLDPs for (long sw: switches) { IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) continue; if (iofSwitch.getEnabledPorts() != null) { for (OFPhysicalPort ofp: iofSwitch.getEnabledPorts()) { if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) continue; if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber())) continue; // sends forward LLDP only non-fastports. sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false); // If the switch port is not alreayd in the maintenance // queue, add it. NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber()); addToMaintenanceQueue(npt); } } } } protected void setControllerTLV() { //Setting the controllerTLVValue based on current nano time, //controller's IP address, and the network interface object hash //the corresponding IP address. final int prime = 7867; InetAddress localIPAddress = null; NetworkInterface localInterface = null; byte[] controllerTLVValue = new byte[] {0, 0, 0, 0, 0, 0, 0, 0}; // 8 byte value. ByteBuffer bb = ByteBuffer.allocate(10); try{ localIPAddress = java.net.InetAddress.getLocalHost(); localInterface = NetworkInterface.getByInetAddress(localIPAddress); } catch (Exception e) { e.printStackTrace(); } long result = System.nanoTime(); if (localIPAddress != null) result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress()); if (localInterface != null) result = result * prime + localInterface.hashCode(); // set the first 4 bits to 0. result = result & (0x0fffffffffffffffL); bb.putLong(result); bb.rewind(); bb.get(controllerTLVValue, 0, 8); this.controllerTLV = new LLDPTLV().setType((byte) 0x0c).setLength((short) controllerTLVValue.length).setValue(controllerTLVValue); } @Override public String getName() { return "linkdiscovery"; } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { switch (msg.getType()) { case PACKET_IN: return this.handlePacketIn(sw.getId(), (OFPacketIn) msg, cntx); case PORT_STATUS: return this.handlePortStatus(sw.getId(), (OFPortStatus) msg); default: break; } return Command.CONTINUE; } private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) { // If LLDP is suppressed on this port, ignore received packet as well IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) { return Command.STOP; } if (isLinkDiscoverySuppressed(sw, pi.getInPort())) return Command.STOP; // If this is a malformed LLDP, or not from us, exit if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) return Command.CONTINUE; long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong(); long otherId = 0; boolean myLLDP = false; Boolean isReverse = null; ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue()); portBB.position(1); Short remotePort = portBB.getShort(); IOFSwitch remoteSwitch = null; // Verify this LLDP packet matches what we're looking for for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) { if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 && lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 && lldptlv.getValue()[2] == (byte)0xe1 && lldptlv.getValue()[3] == 0x0) { ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue()); remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4)); } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8){ otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong(); if (myId == otherId) myLLDP = true; } else if (lldptlv.getType() == TLV_DIRECTION_TYPE && lldptlv.getLength() == TLV_DIRECTION_LENGTH) { if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) isReverse = false; else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) isReverse = true; } } if (myLLDP == false) { // This is not the LLDP sent by this controller. // If the LLDP message has multicast bit set, then we need to broadcast // the packet as a regular packet. if (isStandard) { if (log.isTraceEnabled()) { log.trace("Getting standard LLDP from a different controller and quelching it."); } return Command.STOP; } else if (myId < otherId) { if (log.isTraceEnabled()) { log.trace("Getting BDDP packets from a different controller" + "and letting it go through normal processing chain."); } return Command.CONTINUE; } } if (remoteSwitch == null) { // Ignore LLDPs not generated by Floodlight, or from a switch that has recently // disconnected, or from a switch connected to another Floodlight instance if (log.isTraceEnabled()) { log.trace("Received LLDP from remote switch not connected to the controller"); } return Command.STOP; } if (!remoteSwitch.portEnabled(remotePort)) { if (log.isTraceEnabled()) { log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort); } return Command.STOP; } if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(), remotePort))) { if (log.isTraceEnabled()) { log.trace("Ignoring link with suppressed src port: switch {} port {}", remoteSwitch, remotePort); } return Command.STOP; } if (!iofSwitch.portEnabled(pi.getInPort())) { if (log.isTraceEnabled()) { log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort()); } return Command.STOP; } OFPhysicalPort physicalPort = remoteSwitch.getPort(remotePort); int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0; physicalPort = iofSwitch.getPort(pi.getInPort()); int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0; // Store the time of update to this link, and push it out to routingEngine Link lt = new Link(remoteSwitch.getId(), remotePort, iofSwitch.getId(), pi.getInPort()); Long lastLldpTime = null; Long lastBddpTime = null; Long firstSeenTime = System.currentTimeMillis(); if (isStandard) lastLldpTime = System.currentTimeMillis(); else lastBddpTime = System.currentTimeMillis(); LinkInfo newLinkInfo = new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime, srcPortState, dstPortState); addOrUpdateLink(lt, newLinkInfo); // Check if reverse link exists. // If it doesn't exist and if the forward link was seen // first seen within a small interval, send probe on the // reverse link. newLinkInfo = links.get(lt); if (newLinkInfo != null && isStandard && isReverse == false) { Link reverseLink = new Link(lt.getDst(), lt.getDstPort(), lt.getSrc(), lt.getSrcPort()); LinkInfo reverseInfo = links.get(reverseLink); if (reverseInfo == null) { // the reverse link does not exist. if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) { this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true); } } } // If the received packet is a BDDP packet, then create a reverse BDDP // link as well. if (!isStandard) { Link reverseLink = new Link(lt.getDst(), lt.getDstPort(), lt.getSrc(), lt.getSrcPort()); // srcPortState and dstPort state are reversed. LinkInfo reverseInfo = new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime, dstPortState, srcPortState); addOrUpdateLink(reverseLink, reverseInfo); } // Remove the node ports from the quarantine and maintenance queues. NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort()); removeFromQuarantineQueue(nptSrc); removeFromMaintenanceQueue(nptSrc); removeFromQuarantineQueue(nptDst); removeFromMaintenanceQueue(nptDst); // Consume this message return Command.STOP; } protected Command handlePacketIn(long sw, OFPacketIn pi, FloodlightContext cntx) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); if(eth.getEtherType() == Ethernet.TYPE_BSN) { BSN bsn = (BSN) eth.getPayload(); if (bsn == null) return Command.STOP; if (bsn.getPayload() == null) return Command.STOP; // It could be a packet other than BSN LLDP, therefore // continue with the regular processing. if (bsn.getPayload() instanceof LLDP == false) return Command.CONTINUE; return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx); } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) { return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx); } else if (eth.getEtherType() < 1500) { long destMac = eth.getDestinationMAC().toLong(); if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE){ if (log.isTraceEnabled()) { log.trace("Ignoring packet addressed to 802.1D/Q " + "reserved address."); } return Command.STOP; } } // If packet-in is from a quarantine port, stop processing. NodePortTuple npt = new NodePortTuple(sw, pi.getInPort()); if (quarantineQueue.contains(npt)) return Command.STOP; return Command.CONTINUE; } protected UpdateOperation getUpdateOperation(int srcPortState, int dstPortState) { boolean added = (((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue()) && ((dstPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue())); if (added) return UpdateOperation.LINK_UPDATED; return UpdateOperation.LINK_REMOVED; } protected UpdateOperation getUpdateOperation(int srcPortState) { boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue()); if (portUp) return UpdateOperation.PORT_UP; else return UpdateOperation.PORT_DOWN; } protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) { NodePortTuple srcNpt, dstNpt; boolean linkChanged = false; lock.writeLock().lock(); try { // put the new info. if an old info exists, it will be returned. LinkInfo oldInfo = links.put(lt, newInfo); if (oldInfo != null && oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime()); if (log.isTraceEnabled()) { log.trace("addOrUpdateLink: {} {}", lt, (newInfo.getMulticastValidTime()!=null) ? "multicast" : "unicast"); } UpdateOperation updateOperation = null; linkChanged = false; srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort()); if (oldInfo == null) { // index it by switch source if (!switchLinks.containsKey(lt.getSrc())) switchLinks.put(lt.getSrc(), new HashSet()); switchLinks.get(lt.getSrc()).add(lt); // index it by switch dest if (!switchLinks.containsKey(lt.getDst())) switchLinks.put(lt.getDst(), new HashSet()); switchLinks.get(lt.getDst()).add(lt); // index both ends by switch:port if (!portLinks.containsKey(srcNpt)) portLinks.put(srcNpt, new HashSet()); portLinks.get(srcNpt).add(lt); if (!portLinks.containsKey(dstNpt)) portLinks.put(dstNpt, new HashSet()); portLinks.get(dstNpt).add(lt); // Add to portNOFLinks if the unicast valid time is null if (newInfo.getUnicastValidTime() == null) addLinkToBroadcastDomain(lt); writeLinkToStorage(lt, newInfo); updateOperation = UpdateOperation.LINK_UPDATED; linkChanged = true; // Add to event history evHistTopoLink(lt.getSrc(), lt.getDst(), lt.getSrcPort(), lt.getDstPort(), newInfo.getSrcPortState(), newInfo.getDstPortState(), getLinkType(lt, newInfo), EvAction.LINK_ADDED, "LLDP Recvd"); } else { // Since the link info is already there, we need to // update the right fields. if (newInfo.getUnicastValidTime() == null) { // This is due to a multicast LLDP, so copy the old unicast // value. if (oldInfo.getUnicastValidTime() != null) { newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime()); } } else if (newInfo.getMulticastValidTime() == null) { // This is due to a unicast LLDP, so copy the old multicast // value. if (oldInfo.getMulticastValidTime() != null) { newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime()); } } Long oldTime = oldInfo.getUnicastValidTime(); Long newTime = newInfo.getUnicastValidTime(); // the link has changed its state between openflow and non-openflow // if the unicastValidTimes are null or not null if (oldTime != null & newTime == null) { // openflow -> non-openflow transition // we need to add the link tuple to the portNOFLinks addLinkToBroadcastDomain(lt); linkChanged = true; } else if (oldTime == null & newTime != null) { // non-openflow -> openflow transition // we need to remove the link from the portNOFLinks removeLinkFromBroadcastDomain(lt); linkChanged = true; } // Only update the port states if they've changed if (newInfo.getSrcPortState().intValue() != oldInfo.getSrcPortState().intValue() || newInfo.getDstPortState().intValue() != oldInfo.getDstPortState().intValue()) linkChanged = true; // Write changes to storage. This will always write the updated // valid time, plus the port states if they've changed (i.e. if // they weren't set to null in the previous block of code. writeLinkToStorage(lt, newInfo); if (linkChanged) { updateOperation = getUpdateOperation(newInfo.getSrcPortState(), newInfo.getDstPortState()); if (log.isTraceEnabled()) { log.trace("Updated link {}", lt); } // Add to event history evHistTopoLink(lt.getSrc(), lt.getDst(), lt.getSrcPort(), lt.getDstPort(), newInfo.getSrcPortState(), newInfo.getDstPortState(), getLinkType(lt, newInfo), EvAction.LINK_PORT_STATE_UPDATED, "LLDP Recvd"); } } if (linkChanged) { // find out if the link was added or removed here. updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), lt.getDst(), lt.getDstPort(), getLinkType(lt, newInfo), updateOperation)); } } finally { lock.writeLock().unlock(); } return linkChanged; } public Map> getSwitchLinks() { return this.switchLinks; } /** * Removes links from memory and storage. * @param links The List of @LinkTuple to delete. */ protected void deleteLinks(List links, String reason) { NodePortTuple srcNpt, dstNpt; lock.writeLock().lock(); try { for (Link lt : links) { srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); dstNpt =new NodePortTuple(lt.getDst(), lt.getDstPort()); switchLinks.get(lt.getSrc()).remove(lt); switchLinks.get(lt.getDst()).remove(lt); if (switchLinks.containsKey(lt.getSrc()) && switchLinks.get(lt.getSrc()).isEmpty()) this.switchLinks.remove(lt.getSrc()); if (this.switchLinks.containsKey(lt.getDst()) && this.switchLinks.get(lt.getDst()).isEmpty()) this.switchLinks.remove(lt.getDst()); if (this.portLinks.get(srcNpt) != null) { this.portLinks.get(srcNpt).remove(lt); if (this.portLinks.get(srcNpt).isEmpty()) this.portLinks.remove(srcNpt); } if (this.portLinks.get(dstNpt) != null) { this.portLinks.get(dstNpt).remove(lt); if (this.portLinks.get(dstNpt).isEmpty()) this.portLinks.remove(dstNpt); } LinkInfo info = this.links.remove(lt); updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), lt.getDst(), lt.getDstPort(), getLinkType(lt, info), UpdateOperation.LINK_REMOVED)); // Update Event History evHistTopoLink(lt.getSrc(), lt.getDst(), lt.getSrcPort(), lt.getDstPort(), 0, 0, // Port states ILinkDiscovery.LinkType.INVALID_LINK, EvAction.LINK_DELETED, reason); // remove link from storage. removeLinkFromStorage(lt); // TODO Whenever link is removed, it has to checked if // the switchports must be added to quarantine. if (log.isTraceEnabled()) { log.trace("Deleted link {}", lt); } } } finally { lock.writeLock().unlock(); } } /** * Handles an OFPortStatus message from a switch. We will add or * delete LinkTupes as well re-compute the topology if needed. * @param sw The IOFSwitch that sent the port status message * @param ps The OFPortStatus message * @return The Command to continue or stop after we process this message */ protected Command handlePortStatus(long sw, OFPortStatus ps) { IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) return Command.CONTINUE; if (log.isTraceEnabled()) { log.trace("handlePortStatus: Switch {} port #{} reason {}; " + "config is {} state is {}", new Object[] {iofSwitch.getStringId(), ps.getDesc().getPortNumber(), ps.getReason(), ps.getDesc().getConfig(), ps.getDesc().getState()}); } short port = ps.getDesc().getPortNumber(); NodePortTuple npt = new NodePortTuple(sw, port); boolean linkDeleted = false; boolean linkInfoChanged = false; lock.writeLock().lock(); try { // if ps is a delete, or a modify where the port is down or // configured down if ((byte)OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() || ((byte)OFPortReason.OFPPR_MODIFY.ordinal() == ps.getReason() && !portEnabled(ps.getDesc()))) { deleteLinksOnPort(npt, "Port Status Changed"); LDUpdate update = new LDUpdate(sw, port, UpdateOperation.PORT_DOWN); updates.add(update); linkDeleted = true; } else if (ps.getReason() == (byte)OFPortReason.OFPPR_MODIFY.ordinal()) { // If ps is a port modification and the port state has changed // that affects links in the topology if (this.portLinks.containsKey(npt)) { for (Link lt: this.portLinks.get(npt)) { LinkInfo linkInfo = links.get(lt); assert(linkInfo != null); Integer updatedSrcPortState = null; Integer updatedDstPortState = null; if (lt.getSrc() == npt.getNodeId() && lt.getSrcPort() == npt.getPortId() && (linkInfo.getSrcPortState() != ps.getDesc().getState())) { updatedSrcPortState = ps.getDesc().getState(); linkInfo.setSrcPortState(updatedSrcPortState); } if (lt.getDst() == npt.getNodeId() && lt.getDstPort() == npt.getPortId() && (linkInfo.getDstPortState() != ps.getDesc().getState())) { updatedDstPortState = ps.getDesc().getState(); linkInfo.setDstPortState(updatedDstPortState); } if ((updatedSrcPortState != null) || (updatedDstPortState != null)) { // The link is already known to link discovery // manager and the status has changed, therefore // send an LDUpdate. UpdateOperation operation = getUpdateOperation(linkInfo.getSrcPortState(), linkInfo.getDstPortState()); updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), lt.getDst(), lt.getDstPort(), getLinkType(lt, linkInfo), operation)); writeLinkToStorage(lt, linkInfo); linkInfoChanged = true; } } } UpdateOperation operation = getUpdateOperation(ps.getDesc().getState()); updates.add(new LDUpdate(sw, port, operation)); } if (!linkDeleted && !linkInfoChanged){ if (log.isTraceEnabled()) { log.trace("handlePortStatus: Switch {} port #{} reason {};"+ " no links to update/remove", new Object[] {HexString.toHexString(sw), ps.getDesc().getPortNumber(), ps.getReason()}); } } } finally { lock.writeLock().unlock(); } if (!linkDeleted) { // Send LLDP right away when port state is changed for faster // cluster-merge. If it is a link delete then there is not need // to send the LLDPs right away and instead we wait for the LLDPs // to be sent on the timer as it is normally done // do it outside the write-lock // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS); processNewPort(npt.getNodeId(), npt.getPortId()); } return Command.CONTINUE; } /** * Process a new port. * If link discovery is disabled on the port, then do nothing. * If autoportfast feature is enabled and the port is a fast port, then * do nothing. * Otherwise, send LLDP message. Add the port to quarantine. * @param sw * @param p */ private void processNewPort(long sw, short p) { if (isLinkDiscoverySuppressed(sw, p)) { // Do nothing as link discovery is suppressed. } else if (autoPortFastFeature && isFastPort(sw, p)) { // Do nothing as the port is a fast port. } else { NodePortTuple npt = new NodePortTuple(sw, p); discover(sw, p); // if it is not a fast port, add it to quarantine. if (!isFastPort(sw, p)) { addToQuarantineQueue(npt); } else { // Add to maintenance queue to ensure that BDDP packets // are sent out. addToMaintenanceQueue(npt); } } } /** * We send out LLDP messages when a switch is added to discover the topology * @param sw The IOFSwitch that connected to the controller */ @Override public void addedSwitch(IOFSwitch sw) { if (sw.getEnabledPorts() != null) { for (Short p : sw.getEnabledPortNumbers()) { processNewPort(sw.getId(), p); } } // Update event history evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None"); LDUpdate update = new LDUpdate(sw.getId(), null, UpdateOperation.SWITCH_UPDATED); updates.add(update); } /** * When a switch disconnects we remove any links from our map and notify. * @param The id of the switch */ @Override public void removedSwitch(IOFSwitch iofSwitch) { // Update event history long sw = iofSwitch.getId(); evHistTopoSwitch(iofSwitch, EvAction.SWITCH_DISCONNECTED, "None"); List eraseList = new ArrayList(); lock.writeLock().lock(); try { if (switchLinks.containsKey(sw)) { if (log.isTraceEnabled()) { log.trace("Handle switchRemoved. Switch {}; removing links {}", HexString.toHexString(sw), switchLinks.get(sw)); } // add all tuples with an endpoint on this switch to erase list eraseList.addAll(switchLinks.get(sw)); deleteLinks(eraseList, "Switch Removed"); // Send a switch removed update LDUpdate update = new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED); updates.add(update); } } finally { lock.writeLock().unlock(); } } /** * We don't react the port changed notifications here. we listen for * OFPortStatus messages directly. Might consider using this notifier * instead */ @Override public void switchPortChanged(Long switchId) { // no-op } /** * Delete links incident on a given switch port. * @param npt * @param reason */ protected void deleteLinksOnPort(NodePortTuple npt, String reason) { List eraseList = new ArrayList(); if (this.portLinks.containsKey(npt)) { if (log.isTraceEnabled()) { log.trace("handlePortStatus: Switch {} port #{} " + "removing links {}", new Object[] {HexString.toHexString(npt.getNodeId()), npt.getPortId(), this.portLinks.get(npt)}); } eraseList.addAll(this.portLinks.get(npt)); deleteLinks(eraseList, reason); } } /** * Iterates through the list of links and deletes if the * last discovery message reception time exceeds timeout values. */ protected void timeoutLinks() { List eraseList = new ArrayList(); Long curTime = System.currentTimeMillis(); boolean linkChanged = false; // reentrant required here because deleteLink also write locks lock.writeLock().lock(); try { Iterator> it = this.links.entrySet().iterator(); while (it.hasNext()) { Entry entry = it.next(); Link lt = entry.getKey(); LinkInfo info = entry.getValue(); // Timeout the unicast and multicast LLDP valid times // independently. if ((info.getUnicastValidTime() != null) && (info.getUnicastValidTime() + (this.LINK_TIMEOUT * 1000) < curTime)){ info.setUnicastValidTime(null); if (info.getMulticastValidTime() != null) addLinkToBroadcastDomain(lt); // Note that even if mTime becomes null later on, // the link would be deleted, which would trigger updateClusters(). linkChanged = true; } if ((info.getMulticastValidTime()!= null) && (info.getMulticastValidTime()+ (this.LINK_TIMEOUT * 1000) < curTime)) { info.setMulticastValidTime(null); // if uTime is not null, then link will remain as openflow // link. If uTime is null, it will be deleted. So, we // don't care about linkChanged flag here. removeLinkFromBroadcastDomain(lt); linkChanged = true; } // Add to the erase list only if the unicast // time is null. if (info.getUnicastValidTime() == null && info.getMulticastValidTime() == null){ eraseList.add(entry.getKey()); } else if (linkChanged) { UpdateOperation operation; operation = getUpdateOperation(info.getSrcPortState(), info.getDstPortState()); updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), lt.getDst(), lt.getDstPort(), getLinkType(lt, info), operation)); } } // if any link was deleted or any link was changed. if ((eraseList.size() > 0) || linkChanged) { deleteLinks(eraseList, "LLDP timeout"); } } finally { lock.writeLock().unlock(); } } private boolean portEnabled(OFPhysicalPort port) { if (port == null) return false; if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) return false; if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) return false; // Port STP state doesn't work with multiple VLANs, so ignore it for now // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()) // return false; return true; } public Map> getPortBroadcastDomainLinks() { return portBroadcastDomainLinks; } @Override public Map getLinks() { lock.readLock().lock(); Map result; try { result = new HashMap(links); } finally { lock.readLock().unlock(); } return result; } protected void addLinkToBroadcastDomain(Link lt) { NodePortTuple srcNpt, dstNpt; srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort()); if (!portBroadcastDomainLinks.containsKey(lt.getSrc())) portBroadcastDomainLinks.put(srcNpt, new HashSet()); portBroadcastDomainLinks.get(srcNpt).add(lt); if (!portBroadcastDomainLinks.containsKey(lt.getDst())) portBroadcastDomainLinks.put(dstNpt, new HashSet()); portBroadcastDomainLinks.get(dstNpt).add(lt); } protected void removeLinkFromBroadcastDomain(Link lt) { NodePortTuple srcNpt, dstNpt; srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort()); if (portBroadcastDomainLinks.containsKey(srcNpt)) { portBroadcastDomainLinks.get(srcNpt).remove(lt); if (portBroadcastDomainLinks.get(srcNpt).isEmpty()) portBroadcastDomainLinks.remove(srcNpt); } if (portBroadcastDomainLinks.containsKey(dstNpt)) { portBroadcastDomainLinks.get(dstNpt).remove(lt); if (portBroadcastDomainLinks.get(dstNpt).isEmpty()) portBroadcastDomainLinks.remove(dstNpt); } } // STORAGE METHODS /** * Deletes all links from storage */ void clearAllLinks() { storageSource.deleteRowsAsync(LINK_TABLE_NAME, null); } /** * Gets the storage key for a LinkTuple * @param lt The LinkTuple to get * @return The storage key as a String */ private String getLinkId(Link lt) { return HexString.toHexString(lt.getSrc()) + "-" + lt.getSrcPort() + "-" + HexString.toHexString(lt.getDst())+ "-" + lt.getDstPort(); } /** * Writes a LinkTuple and corresponding LinkInfo to storage * @param lt The LinkTuple to write * @param linkInfo The LinkInfo to write */ protected void writeLinkToStorage(Link lt, LinkInfo linkInfo) { LinkType type = getLinkType(lt, linkInfo); // Write only direct links. Do not write links to external // L2 network. // if (type != LinkType.DIRECT_LINK && type != LinkType.TUNNEL) { // return; // } Map rowValues = new HashMap(); String id = getLinkId(lt); rowValues.put(LINK_ID, id); rowValues.put(LINK_VALID_TIME, linkInfo.getUnicastValidTime()); String srcDpid = HexString.toHexString(lt.getSrc()); rowValues.put(LINK_SRC_SWITCH, srcDpid); rowValues.put(LINK_SRC_PORT, lt.getSrcPort()); if (type == LinkType.DIRECT_LINK) rowValues.put(LINK_TYPE, "internal"); else if (type == LinkType.MULTIHOP_LINK) rowValues.put(LINK_TYPE, "external"); else if (type == LinkType.TUNNEL) rowValues.put(LINK_TYPE, "tunnel"); else rowValues.put(LINK_TYPE, "invalid"); if (linkInfo.linkStpBlocked()) { if (log.isTraceEnabled()) { log.trace("writeLink, link {}, info {}, srcPortState Blocked", lt, linkInfo); } rowValues.put(LINK_SRC_PORT_STATE, OFPhysicalPort.OFPortState.OFPPS_STP_BLOCK.getValue()); } else { if (log.isTraceEnabled()) { log.trace("writeLink, link {}, info {}, srcPortState {}", new Object[]{ lt, linkInfo, linkInfo.getSrcPortState() }); } rowValues.put(LINK_SRC_PORT_STATE, linkInfo.getSrcPortState()); } String dstDpid = HexString.toHexString(lt.getDst()); rowValues.put(LINK_DST_SWITCH, dstDpid); rowValues.put(LINK_DST_PORT, lt.getDstPort()); if (linkInfo.linkStpBlocked()) { if (log.isTraceEnabled()) { log.trace("writeLink, link {}, info {}, dstPortState Blocked", lt, linkInfo); } rowValues.put(LINK_DST_PORT_STATE, OFPhysicalPort.OFPortState.OFPPS_STP_BLOCK.getValue()); } else { if (log.isTraceEnabled()) { log.trace("writeLink, link {}, info {}, dstPortState {}", new Object[]{ lt, linkInfo, linkInfo.getDstPortState() }); } rowValues.put(LINK_DST_PORT_STATE, linkInfo.getDstPortState()); } storageSource.updateRowAsync(LINK_TABLE_NAME, rowValues); } public Long readLinkValidTime(Link lt) { // FIXME: We're not currently using this right now, but if we start // to use this again, we probably shouldn't use it in its current // form, because it's doing synchronous storage calls. Depending // on the context this may still be OK, but if it's being called // on the packet in processing thread it should be reworked to // use asynchronous storage calls. Long validTime = null; IResultSet resultSet = null; try { String[] columns = { LINK_VALID_TIME }; String id = getLinkId(lt); resultSet = storageSource.executeQuery(LINK_TABLE_NAME, columns, new OperatorPredicate(LINK_ID, OperatorPredicate.Operator.EQ, id), null); if (resultSet.next()) validTime = resultSet.getLong(LINK_VALID_TIME); } finally { if (resultSet != null) resultSet.close(); } return validTime; } /** * Removes a link from storage using an asynchronous call. * @param lt The LinkTuple to delete. */ protected void removeLinkFromStorage(Link lt) { String id = getLinkId(lt); storageSource.deleteRowAsync(LINK_TABLE_NAME, id); } @Override public void addListener(ILinkDiscoveryListener listener) { linkDiscoveryAware.add(listener); } /** * Register a link discovery aware component * @param linkDiscoveryAwareComponent */ public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) { // TODO make this a copy on write set or lock it somehow this.linkDiscoveryAware.add(linkDiscoveryAwareComponent); } /** * Deregister a link discovery aware component * @param linkDiscoveryAwareComponent */ public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) { // TODO make this a copy on write set or lock it somehow this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent); } /** * Sets the IStorageSource to use for ITology * @param storageSource the storage source to use */ public void setStorageSource(IStorageSourceService storageSource) { this.storageSource = storageSource; } /** * Gets the storage source for this ITopology * @return The IStorageSource ITopology is writing to */ public IStorageSourceService getStorageSource() { return storageSource; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return false; } @Override public void rowsModified(String tableName, Set rowKeys) { Map switches = floodlightProvider.getSwitches(); ArrayList updated_switches = new ArrayList(); for(Object key: rowKeys) { Long swId = new Long(HexString.toLong((String)key)); if (switches.containsKey(swId)) { IOFSwitch sw = switches.get(swId); boolean curr_status = sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH); boolean new_status = false; IResultSet resultSet = null; try { resultSet = storageSource.getRow(tableName, key); for (Iterator it = resultSet.iterator(); it.hasNext();) { // In case of multiple rows, use the status in last row? Map row = it.next().getRow(); if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) { new_status = ((String)row.get(SWITCH_CONFIG_CORE_SWITCH)).equals("true"); } } } finally { if (resultSet != null) resultSet.close(); } if (curr_status != new_status) { updated_switches.add(sw); } } else { if (log.isTraceEnabled()) { log.trace("Update for switch which has no entry in switch " + "list (dpid={}), a delete action.", (String)key); } } } for (IOFSwitch sw : updated_switches) { // Set SWITCH_IS_CORE_SWITCH to it's inverse value if (sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH)) { sw.removeAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH); if (log.isTraceEnabled()) { log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", sw); } updates.add(new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH, UpdateOperation.SWITCH_UPDATED)); } else { sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true)); if (log.isTraceEnabled()) { log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw); } updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH, UpdateOperation.SWITCH_UPDATED)); } } } @Override public void rowsDeleted(String tableName, Set rowKeys) { // Ignore delete events, the switch delete will do the right thing on it's own } // IFloodlightModule classes @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(ILinkDiscoveryService.class); //l.add(ITopologyService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); // We are the class that implements the service m.put(ILinkDiscoveryService.class, this); return m; } @Override public Collection> getModuleDependencies() { Collection> l = new ArrayList>(); l.add(IFloodlightProviderService.class); l.add(IStorageSourceService.class); l.add(IThreadPoolService.class); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); storageSource = context.getServiceImpl(IStorageSourceService.class); threadPool = context.getServiceImpl(IThreadPoolService.class); restApi = context.getServiceImpl(IRestApiService.class); // Set the autoportfast feature to false. this.autoPortFastFeature = false; // We create this here because there is no ordering guarantee this.linkDiscoveryAware = new ArrayList(); this.lock = new ReentrantReadWriteLock(); this.updates = new LinkedBlockingQueue(); this.links = new HashMap(); this.portLinks = new HashMap>(); this.suppressLinkDiscovery = Collections.synchronizedSet(new HashSet()); this.portBroadcastDomainLinks = new HashMap>(); this.switchLinks = new HashMap>(); this.quarantineQueue = new LinkedBlockingQueue(); this.maintenanceQueue = new LinkedBlockingQueue(); this.evHistTopologySwitch = new EventHistory("Topology: Switch"); this.evHistTopologyLink = new EventHistory("Topology: Link"); this.evHistTopologyCluster = new EventHistory("Topology: Cluster"); } @Override @LogMessageDocs({ @LogMessageDoc(level="ERROR", message="No storage source found.", explanation="Storage source was not initialized; cannot initialize " + "link discovery.", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG), @LogMessageDoc(level="ERROR", message="Error in installing listener for " + "switch config table {table}", explanation="Failed to install storage notification for the " + "switch config table", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG), @LogMessageDoc(level="ERROR", message="No storage source found.", explanation="Storage source was not initialized; cannot initialize " + "link discovery.", recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG), @LogMessageDoc(level="ERROR", message="Exception in LLDP send timer.", explanation="An unknown error occured while sending LLDP " + "messages to switches.", recommendation=LogMessageDoc.CHECK_SWITCH) }) public void startUp(FloodlightModuleContext context) { // Create our storage tables if (storageSource == null) { log.error("No storage source found."); return; } storageSource.createTable(LINK_TABLE_NAME, null); storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID); storageSource.deleteMatchingRows(LINK_TABLE_NAME, null); // Register for storage updates for the switch table try { storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this); } catch (StorageException ex) { log.error("Error in installing listener for " + "switch table {}", SWITCH_CONFIG_TABLE_NAME); } ScheduledExecutorService ses = threadPool.getScheduledExecutor(); // To be started by the first switch connection discoveryTask = new SingletonTask(ses, new Runnable() { @Override public void run() { try { discoverLinks(); } catch (StorageException e) { log.error("Storage exception in LLDP send timer; " + "terminating process", e); floodlightProvider.terminate(); } catch (Exception e) { log.error("Exception in LLDP send timer.", e); } finally { if (!shuttingDown) { // null role implies HA mode is not enabled. Role role = floodlightProvider.getRole(); if (role == null || role == Role.MASTER) { log.trace("Rescheduling discovery task as role = {}", role); discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS); } else { log.trace("Stopped LLDP rescheduling due to role = {}.", role); } } } } }); // null role implies HA mode is not enabled. Role role = floodlightProvider.getRole(); if (role == null || role == Role.MASTER) { log.trace("Setup: Rescheduling discovery task. role = {}", role); discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS); } else { log.trace("Setup: Not scheduling LLDP as role = {}.", role); } // Setup the BDDP task. It is invoked whenever switch port tuples // are added to the quarantine list. bddpTask = new SingletonTask(ses, new QuarantineWorker()); bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS); updatesThread = new Thread(new Runnable () { @Override public void run() { while (true) { try { doUpdatesThread(); } catch (InterruptedException e) { return; } } }}, "Topology Updates"); updatesThread.start(); // Register for the OpenFlow messages we want to receive floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this); // Register for switch updates floodlightProvider.addOFSwitchListener(this); floodlightProvider.addHAListener(this); floodlightProvider.addInfoProvider("summary", this); if (restApi != null) restApi.addRestletRoutable(new LinkDiscoveryWebRoutable()); setControllerTLV(); } // **************************************************** // Topology Manager's Event History members and methods // **************************************************** // Topology Manager event history public EventHistory evHistTopologySwitch; public EventHistory evHistTopologyLink; public EventHistory evHistTopologyCluster; public EventHistoryTopologySwitch evTopoSwitch; public EventHistoryTopologyLink evTopoLink; public EventHistoryTopologyCluster evTopoCluster; // Switch Added/Deleted private void evHistTopoSwitch(IOFSwitch sw, EvAction actn, String reason) { if (evTopoSwitch == null) { evTopoSwitch = new EventHistoryTopologySwitch(); } evTopoSwitch.dpid = sw.getId(); if ((sw.getChannel() != null) && (SocketAddress.class.isInstance( sw.getChannel().getRemoteAddress()))) { evTopoSwitch.ipv4Addr = IPv4.toIPv4Address(((InetSocketAddress)(sw.getChannel(). getRemoteAddress())).getAddress().getAddress()); evTopoSwitch.l4Port = ((InetSocketAddress)(sw.getChannel(). getRemoteAddress())).getPort(); } else { evTopoSwitch.ipv4Addr = 0; evTopoSwitch.l4Port = 0; } evTopoSwitch.reason = reason; evTopoSwitch = evHistTopologySwitch.put(evTopoSwitch, actn); } private void evHistTopoLink(long srcDpid, long dstDpid, short srcPort, short dstPort, int srcPortState, int dstPortState, ILinkDiscovery.LinkType linkType, EvAction actn, String reason) { if (evTopoLink == null) { evTopoLink = new EventHistoryTopologyLink(); } evTopoLink.srcSwDpid = srcDpid; evTopoLink.dstSwDpid = dstDpid; evTopoLink.srcSwport = srcPort & 0xffff; evTopoLink.dstSwport = dstPort & 0xffff; evTopoLink.srcPortState = srcPortState; evTopoLink.dstPortState = dstPortState; evTopoLink.reason = reason; switch (linkType) { case DIRECT_LINK: evTopoLink.linkType = "DIRECT_LINK"; break; case MULTIHOP_LINK: evTopoLink.linkType = "MULTIHOP_LINK"; break; case TUNNEL: evTopoLink.linkType = "TUNNEL"; break; case INVALID_LINK: default: evTopoLink.linkType = "Unknown"; break; } evTopoLink = evHistTopologyLink.put(evTopoLink, actn); } public void evHistTopoCluster(long dpid, long clusterIdOld, long clusterIdNew, EvAction action, String reason) { if (evTopoCluster == null) { evTopoCluster = new EventHistoryTopologyCluster(); } evTopoCluster.dpid = dpid; evTopoCluster.clusterIdOld = clusterIdOld; evTopoCluster.clusterIdNew = clusterIdNew; evTopoCluster.reason = reason; evTopoCluster = evHistTopologyCluster.put(evTopoCluster, action); } @Override public Map getInfo(String type) { if (!"summary".equals(type)) return null; Map info = new HashMap(); int num_links = 0; for (Set links : switchLinks.values()) num_links += links.size(); info.put("# inter-switch links", num_links / 2); return info; } // IHARoleListener @Override public void roleChanged(Role oldRole, Role newRole) { switch(newRole) { case MASTER: if (oldRole == Role.SLAVE) { if (log.isTraceEnabled()) { log.trace("Sending LLDPs " + "to HA change from SLAVE->MASTER"); } clearAllLinks(); log.debug("Role Change to Master: Rescheduling discovery task."); discoveryTask.reschedule(1, TimeUnit.MICROSECONDS); } break; case SLAVE: if (log.isTraceEnabled()) { log.trace("Clearing links due to " + "HA change to SLAVE"); } switchLinks.clear(); links.clear(); portLinks.clear(); portBroadcastDomainLinks.clear(); discoverOnAllPorts(); break; default: break; } } @Override public void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { // ignore } public boolean isAutoPortFastFeature() { return autoPortFastFeature; } public void setAutoPortFastFeature(boolean autoPortFastFeature) { this.autoPortFastFeature = autoPortFastFeature; } } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java0000664000175000017500000001427012041336206031174 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc.* Originally created by David Erickson, Stanford University ** Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.linkdiscovery; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; import org.openflow.protocol.OFPhysicalPort.OFPortState; public class LinkInfo { public LinkInfo(Long firstSeenTime, Long lastLldpReceivedTime, Long lastBddpReceivedTime, int srcPortState, int dstPortState) { super(); this.srcPortState = srcPortState; this.dstPortState = dstPortState; this.firstSeenTime = firstSeenTime; this.lastLldpReceivedTime = lastLldpReceivedTime; this.lastBddpReceivedTime = lastBddpReceivedTime; } protected Integer srcPortState; protected Integer dstPortState; protected Long firstSeenTime; protected Long lastLldpReceivedTime; /* Standard LLLDP received time */ protected Long lastBddpReceivedTime; /* Modified LLDP received time */ /** The port states stored here are topology's last knowledge of * the state of the port. This mostly mirrors the state * maintained in the port list in IOFSwitch (i.e. the one returned * from getPort), except that during a port status message the * IOFSwitch port state will already have been updated with the * new port state, so topology needs to keep its own copy so that * it can determine if the port state has changed and therefore * requires the new state to be written to storage. */ public boolean linkStpBlocked() { return ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()) || ((dstPortState & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue()); } public Long getFirstSeenTime() { return firstSeenTime; } public void setFirstSeenTime(Long firstSeenTime) { this.firstSeenTime = firstSeenTime; } public Long getUnicastValidTime() { return lastLldpReceivedTime; } public void setUnicastValidTime(Long unicastValidTime) { this.lastLldpReceivedTime = unicastValidTime; } public Long getMulticastValidTime() { return lastBddpReceivedTime; } public void setMulticastValidTime(Long multicastValidTime) { this.lastBddpReceivedTime = multicastValidTime; } public Integer getSrcPortState() { return srcPortState; } public void setSrcPortState(Integer srcPortState) { this.srcPortState = srcPortState; } public Integer getDstPortState() { return dstPortState; } public void setDstPortState(int dstPortState) { this.dstPortState = dstPortState; } public LinkType getLinkType() { if (lastLldpReceivedTime != null) { return LinkType.DIRECT_LINK; } else if (lastBddpReceivedTime != null) { return LinkType.MULTIHOP_LINK; } return LinkType.INVALID_LINK; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 5557; int result = 1; result = prime * result + ((firstSeenTime == null) ? 0 : firstSeenTime.hashCode()); result = prime * result + ((lastLldpReceivedTime == null) ? 0 : lastLldpReceivedTime.hashCode()); result = prime * result + ((lastBddpReceivedTime == null) ? 0 : lastBddpReceivedTime.hashCode()); result = prime * result + ((srcPortState == null) ? 0 : srcPortState.hashCode()); result = prime * result + ((dstPortState == null) ? 0 : dstPortState.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof LinkInfo)) return false; LinkInfo other = (LinkInfo) obj; if (firstSeenTime == null) { if (other.firstSeenTime != null) return false; } else if (!firstSeenTime.equals(other.firstSeenTime)) return false; if (lastLldpReceivedTime == null) { if (other.lastLldpReceivedTime != null) return false; } else if (!lastLldpReceivedTime.equals(other.lastLldpReceivedTime)) return false; if (lastBddpReceivedTime == null) { if (other.lastBddpReceivedTime != null) return false; } else if (!lastBddpReceivedTime.equals(other.lastBddpReceivedTime)) return false; if (srcPortState == null) { if (other.srcPortState != null) return false; } else if (!srcPortState.equals(other.srcPortState)) return false; if (dstPortState == null) { if (other.dstPortState != null) return false; } else if (!dstPortState.equals(other.dstPortState)) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime) + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime) + ", srcPortState=" + ((srcPortState == null) ? "null" : srcPortState) + ", dstPortState=" + ((dstPortState == null) ? "null" : srcPortState) + "]"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryListener.java0000664000175000017500000000156012041336206034065 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.linkdiscovery; public interface ILinkDiscoveryListener extends ILinkDiscovery{ public void linkDiscoveryUpdate(LDUpdate update); } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/0000775000175000017500000000000012041336206027371 5ustar jamespagejamespage././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootfloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.javafloodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.ja0000664000175000017500000000131412041336206034625 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.web; import net.floodlightcontroller.restserver.RestletRoutable; import org.restlet.Context; import org.restlet.routing.Router; public class LinkDiscoveryWebRoutable implements RestletRoutable { /** * Create the Restlet router and bind to the proper resources. */ @Override public Router getRestlet(Context context) { Router router = new Router(context); router.attach("/autoportfast/{state}/json", AutoPortFast.class); // enable/true or disable/false return router; } /** * Set the base path for the Topology */ @Override public String basePath() { return "/wm/linkdiscovery"; } }floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java0000664000175000017500000000433112041336206032630 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.web; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; import net.floodlightcontroller.routing.Link; /** * This class is both the datastructure and the serializer * for a link with the corresponding type of link. * @author alexreimers */ @JsonSerialize(using=LinkWithType.class) public class LinkWithType extends JsonSerializer { public long srcSwDpid; public short srcPort; public int srcPortState; public long dstSwDpid; public short dstPort; public int dstPortState; public LinkType type; // Do NOT delete this, it's required for the serializer public LinkWithType() {} public LinkWithType(Link link, int srcPortState, int dstPortState, LinkType type) { this.srcSwDpid = link.getSrc(); this.srcPort = link.getSrcPort(); this.srcPortState = srcPortState; this.dstSwDpid = link.getDst(); this.dstPort = link.getDstPort(); this.dstPortState = dstPortState; this.type = type; } @Override public void serialize(LinkWithType lwt, JsonGenerator jgen, SerializerProvider arg2) throws IOException, JsonProcessingException { // You ****MUST*** use lwt for the fields as it's actually a different object. jgen.writeStartObject(); jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid)); jgen.writeNumberField("src-port", lwt.srcPort); jgen.writeNumberField("src-port-state", lwt.srcPortState); jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid)); jgen.writeNumberField("dst-port", lwt.dstPort); jgen.writeNumberField("dst-port-state", lwt.dstPortState); jgen.writeStringField("type", lwt.type.toString()); jgen.writeEndObject(); } @Override public Class handledType() { return LinkWithType.class; } }floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java0000664000175000017500000000252312041336206033026 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.web; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.LinkInfo; import net.floodlightcontroller.routing.Link; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; public class LinksResource extends ServerResource { @Get("json") public Set retrieve() { ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes(). get(ILinkDiscoveryService.class.getCanonicalName()); Map links = new HashMap(); Set returnLinkSet = new HashSet(); if (ld != null) { links.putAll(ld.getLinks()); for (Link link: links.keySet()) { LinkInfo info = links.get(link); LinkWithType lwt = new LinkWithType(link, info.getSrcPortState(), info.getDstPortState(), ld.getLinkType(link, info)); returnLinkSet.add(lwt); } } return returnLinkSet; } } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/web/AutoPortFast.java0000664000175000017500000000221612041336206032630 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery.web; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import org.restlet.data.Status; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AutoPortFast extends ServerResource { protected static Logger log = LoggerFactory.getLogger(AutoPortFast.class); @Get("json") public String retrieve() { ILinkDiscoveryService linkDiscovery; linkDiscovery = (ILinkDiscoveryService)getContext().getAttributes(). get(ILinkDiscoveryService.class.getCanonicalName()); String param = ((String)getRequestAttributes().get("state")).toLowerCase(); if (param.equals("enable") || param.equals("true")) { linkDiscovery.setAutoPortFastFeature(true); } else if (param.equals("disable") || param.equals("false")) { linkDiscovery.setAutoPortFastFeature(false); } setStatus(Status.SUCCESS_OK, "OK"); if (linkDiscovery.isAutoPortFastFeature()) return "enabled"; else return "disabled"; } } floodlight-0.90/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java0000664000175000017500000001055412041336206032362 0ustar jamespagejamespagepackage net.floodlightcontroller.linkdiscovery; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.ser.ToStringSerializer; import org.openflow.util.HexString; public interface ILinkDiscovery { @JsonSerialize(using=ToStringSerializer.class) public enum UpdateOperation { LINK_UPDATED("Link Updated"), LINK_REMOVED("Link Removed"), SWITCH_UPDATED("Switch Updated"), SWITCH_REMOVED("Switch Removed"), PORT_UP("Port Up"), PORT_DOWN("Port Down"); private String value; UpdateOperation(String v) { value = v; } @Override public String toString() { return value; } } public class LDUpdate { protected long src; protected short srcPort; protected long dst; protected short dstPort; protected SwitchType srcType; protected LinkType type; protected UpdateOperation operation; public LDUpdate(long src, short srcPort, long dst, short dstPort, ILinkDiscovery.LinkType type, UpdateOperation operation) { this.src = src; this.srcPort = srcPort; this.dst = dst; this.dstPort = dstPort; this.type = type; this.operation = operation; } public LDUpdate(LDUpdate old) { this.src = old.src; this.srcPort = old.srcPort; this.dst = old.dst; this.dstPort = old.dstPort; this.srcType = old.srcType; this.type = old.type; this.operation = old.operation; } // For updtedSwitch(sw) public LDUpdate(long switchId, SwitchType stype, UpdateOperation oper ){ this.operation = oper; this.src = switchId; this.srcType = stype; } // For port up or port down. public LDUpdate(long sw, short port, UpdateOperation operation) { this.src = sw; this.srcPort = port; this.operation = operation; } public long getSrc() { return src; } public short getSrcPort() { return srcPort; } public long getDst() { return dst; } public short getDstPort() { return dstPort; } public SwitchType getSrcType() { return srcType; } public LinkType getType() { return type; } public UpdateOperation getOperation() { return operation; } public void setOperation(UpdateOperation operation) { this.operation = operation; } @Override public String toString() { switch (operation) { case LINK_REMOVED: case LINK_UPDATED: return "LDUpdate [operation=" + operation + ", src=" + HexString.toHexString(src) + ", srcPort=" + srcPort + ", dst=" + HexString.toHexString(dst) + ", dstPort=" + dstPort + ", type=" + type + "]"; case PORT_DOWN: case PORT_UP: return "LDUpdate [operation=" + operation + ", src=" + HexString.toHexString(src) + ", srcPort=" + srcPort + "]"; case SWITCH_REMOVED: case SWITCH_UPDATED: return "LDUpdate [operation=" + operation + ", src=" + HexString.toHexString(src) + "]"; default: return "LDUpdate: Unknown update."; } } } public enum SwitchType { BASIC_SWITCH, CORE_SWITCH }; public enum LinkType { INVALID_LINK { @Override public String toString() { return "invalid"; } }, DIRECT_LINK{ @Override public String toString() { return "internal"; } }, MULTIHOP_LINK { @Override public String toString() { return "external"; } }, TUNNEL { @Override public String toString() { return "tunnel"; } } }; } floodlight-0.90/src/main/java/org/0000775000175000017500000000000012041336206017471 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/0000775000175000017500000000000012041336206021322 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/0000775000175000017500000000000012041336206023163 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/OFEchoRequest.java0000664000175000017500000000505112041336206026503 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * Represents an ofp_echo_request message * * @author Rob Sherwood (rob.sherwood@stanford.edu) */ public class OFEchoRequest extends OFMessage { public static int MINIMUM_LENGTH = 8; byte[] payload; public OFEchoRequest() { super(); this.type = OFType.ECHO_REQUEST; this.length = U16.t(MINIMUM_LENGTH); } @Override public void readFrom(ChannelBuffer bb) { super.readFrom(bb); int datalen = this.getLengthU() - MINIMUM_LENGTH; if (datalen > 0) { this.payload = new byte[datalen]; bb.readBytes(payload); } } /** * @return the payload */ public byte[] getPayload() { return payload; } /** * @param payload * the payload to set */ public void setPayload(byte[] payload) { this.payload = payload; } @Override public void writeTo(ChannelBuffer bb) { super.writeTo(bb); if (payload != null) bb.writeBytes(payload); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(payload); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OFEchoRequest other = (OFEchoRequest) obj; if (!Arrays.equals(payload, other.payload)) return false; return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPacketOut.java0000664000175000017500000001445012041336206026156 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.factory.OFActionFactory; import org.openflow.protocol.factory.OFActionFactoryAware; import org.openflow.util.U16; /** * Represents an ofp_packet_out message * * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 12, 2010 */ public class OFPacketOut extends OFMessage implements OFActionFactoryAware { public static int MINIMUM_LENGTH = 16; public static int BUFFER_ID_NONE = 0xffffffff; protected OFActionFactory actionFactory; protected int bufferId; protected short inPort; protected short actionsLength; protected List actions; protected byte[] packetData; public OFPacketOut() { super(); this.type = OFType.PACKET_OUT; this.length = U16.t(MINIMUM_LENGTH); } /** * Get buffer_id * @return */ public int getBufferId() { return this.bufferId; } /** * Set buffer_id * @param bufferId */ public OFPacketOut setBufferId(int bufferId) { this.bufferId = bufferId; return this; } /** * Returns the packet data * @return */ public byte[] getPacketData() { return this.packetData; } /** * Sets the packet data * @param packetData */ public OFPacketOut setPacketData(byte[] packetData) { this.packetData = packetData; return this; } /** * Get in_port * @return */ public short getInPort() { return this.inPort; } /** * Set in_port * @param inPort */ public OFPacketOut setInPort(short inPort) { this.inPort = inPort; return this; } /** * Set in_port. Convenience method using OFPort enum. * @param inPort */ public OFPacketOut setInPort(OFPort inPort) { this.inPort = inPort.getValue(); return this; } /** * Get actions_len * @return */ public short getActionsLength() { return this.actionsLength; } /** * Get actions_len, unsigned * @return */ public int getActionsLengthU() { return U16.f(this.actionsLength); } /** * Set actions_len * @param actionsLength */ public OFPacketOut setActionsLength(short actionsLength) { this.actionsLength = actionsLength; return this; } /** * Returns the actions contained in this message * @return a list of ordered OFAction objects */ public List getActions() { return this.actions; } /** * Sets the list of actions on this message * @param actions a list of ordered OFAction objects */ public OFPacketOut setActions(List actions) { this.actions = actions; return this; } @Override public void setActionFactory(OFActionFactory actionFactory) { this.actionFactory = actionFactory; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.bufferId = data.readInt(); this.inPort = data.readShort(); this.actionsLength = data.readShort(); if ( this.actionFactory == null) throw new RuntimeException("ActionFactory not set"); this.actions = this.actionFactory.parseActions(data, getActionsLengthU()); this.packetData = new byte[getLengthU() - MINIMUM_LENGTH - getActionsLengthU()]; data.readBytes(this.packetData); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(bufferId); data.writeShort(inPort); data.writeShort(actionsLength); for (OFAction action : actions) { action.writeTo(data); } if (this.packetData != null) data.writeBytes(this.packetData); } @Override public int hashCode() { final int prime = 293; int result = super.hashCode(); result = prime * result + ((actions == null) ? 0 : actions.hashCode()); result = prime * result + actionsLength; result = prime * result + bufferId; result = prime * result + inPort; result = prime * result + Arrays.hashCode(packetData); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFPacketOut)) { return false; } OFPacketOut other = (OFPacketOut) obj; if (actions == null) { if (other.actions != null) { return false; } } else if (!actions.equals(other.actions)) { return false; } if (actionsLength != other.actionsLength) { return false; } if (bufferId != other.bufferId) { return false; } if (inPort != other.inPort) { return false; } if (!Arrays.equals(packetData, other.packetData)) { return false; } return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "OFPacketOut [actionFactory=" + actionFactory + ", actions=" + actions + ", actionsLength=" + actionsLength + ", bufferId=0x" + Integer.toHexString(bufferId) + ", inPort=" + inPort + ", packetData=" + Arrays.toString(packetData) + "]"; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFStatisticsRequest.java0000664000175000017500000000207612041336206027763 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an ofp_stats_request message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFStatisticsRequest extends OFStatisticsMessageBase { public OFStatisticsRequest() { super(); this.type = OFType.STATS_REQUEST; this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFFlowMod.java0000664000175000017500000002424412041336206025630 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.LinkedList; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.factory.OFActionFactory; import org.openflow.protocol.factory.OFActionFactoryAware; import org.openflow.util.U16; /** * Represents an ofp_flow_mod message * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class OFFlowMod extends OFMessage implements OFActionFactoryAware, Cloneable { public static int MINIMUM_LENGTH = 72; public static final short OFPFC_ADD = 0; /* New flow. */ public static final short OFPFC_MODIFY = 1; /* Modify all matching flows. */ public static final short OFPFC_MODIFY_STRICT = 2; /* Modify entry strictly matching wildcards */ public static final short OFPFC_DELETE=3; /* Delete all matching flows. */ public static final short OFPFC_DELETE_STRICT =4; /* Strictly match wildcards and priority. */ // Open Flow Flow Mod Flags. Use "or" operation to set multiple flags public static final short OFPFF_SEND_FLOW_REM = 0x1; // 1 << 0 public static final short OFPFF_CHECK_OVERLAP = 0x2; // 1 << 1 public static final short OFPFF_EMERG = 0x4; // 1 << 2 protected OFActionFactory actionFactory; protected OFMatch match; protected long cookie; protected short command; protected short idleTimeout; protected short hardTimeout; protected short priority; protected int bufferId; protected short outPort; protected short flags; protected List actions; public OFFlowMod() { super(); this.type = OFType.FLOW_MOD; this.length = U16.t(MINIMUM_LENGTH); } /** * Get buffer_id * @return */ public int getBufferId() { return this.bufferId; } /** * Set buffer_id * @param bufferId */ public OFFlowMod setBufferId(int bufferId) { this.bufferId = bufferId; return this; } /** * Get cookie * @return */ public long getCookie() { return this.cookie; } /** * Set cookie * @param cookie */ public OFFlowMod setCookie(long cookie) { this.cookie = cookie; return this; } /** * Get command * @return */ public short getCommand() { return this.command; } /** * Set command * @param command */ public OFFlowMod setCommand(short command) { this.command = command; return this; } /** * Get flags * @return */ public short getFlags() { return this.flags; } /** * Set flags * @param flags */ public OFFlowMod setFlags(short flags) { this.flags = flags; return this; } /** * Get hard_timeout * @return */ public short getHardTimeout() { return this.hardTimeout; } /** * Set hard_timeout * @param hardTimeout */ public OFFlowMod setHardTimeout(short hardTimeout) { this.hardTimeout = hardTimeout; return this; } /** * Get idle_timeout * @return */ public short getIdleTimeout() { return this.idleTimeout; } /** * Set idle_timeout * @param idleTimeout */ public OFFlowMod setIdleTimeout(short idleTimeout) { this.idleTimeout = idleTimeout; return this; } /** * Gets a copy of the OFMatch object for this FlowMod, changes to this * object do not modify the FlowMod * @return */ public OFMatch getMatch() { return this.match; } /** * Set match * @param match */ public OFFlowMod setMatch(OFMatch match) { this.match = match; return this; } /** * Get out_port * @return */ public short getOutPort() { return this.outPort; } /** * Set out_port * @param outPort */ public OFFlowMod setOutPort(short outPort) { this.outPort = outPort; return this; } /** * Set out_port * @param port */ public OFFlowMod setOutPort(OFPort port) { this.outPort = port.getValue(); return this; } /** * Get priority * @return */ public short getPriority() { return this.priority; } /** * Set priority * @param priority */ public OFFlowMod setPriority(short priority) { this.priority = priority; return this; } /** * Returns read-only copies of the actions contained in this Flow Mod * @return a list of ordered OFAction objects */ public List getActions() { return this.actions; } /** * Sets the list of actions this Flow Mod contains * @param actions a list of ordered OFAction objects */ public OFFlowMod setActions(List actions) { this.actions = actions; return this; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); if (this.match == null) this.match = new OFMatch(); this.match.readFrom(data); this.cookie = data.readLong(); this.command = data.readShort(); this.idleTimeout = data.readShort(); this.hardTimeout = data.readShort(); this.priority = data.readShort(); this.bufferId = data.readInt(); this.outPort = data.readShort(); this.flags = data.readShort(); if (this.actionFactory == null) throw new RuntimeException("OFActionFactory not set"); this.actions = this.actionFactory.parseActions(data, getLengthU() - MINIMUM_LENGTH); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); this.match.writeTo(data); data.writeLong(cookie); data.writeShort(command); data.writeShort(idleTimeout); data.writeShort(hardTimeout); data.writeShort(priority); data.writeInt(bufferId); data.writeShort(outPort); data.writeShort(flags); if (actions != null) { for (OFAction action : actions) { action.writeTo(data); } } } @Override public void setActionFactory(OFActionFactory actionFactory) { this.actionFactory = actionFactory; } @Override public int hashCode() { final int prime = 227; int result = super.hashCode(); result = prime * result + ((actions == null) ? 0 : actions.hashCode()); result = prime * result + bufferId; result = prime * result + command; result = prime * result + (int) (cookie ^ (cookie >>> 32)); result = prime * result + flags; result = prime * result + hardTimeout; result = prime * result + idleTimeout; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + outPort; result = prime * result + priority; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFFlowMod)) { return false; } OFFlowMod other = (OFFlowMod) obj; if (actions == null) { if (other.actions != null) { return false; } } else if (!actions.equals(other.actions)) { return false; } if (bufferId != other.bufferId) { return false; } if (command != other.command) { return false; } if (cookie != other.cookie) { return false; } if (flags != other.flags) { return false; } if (hardTimeout != other.hardTimeout) { return false; } if (idleTimeout != other.idleTimeout) { return false; } if (match == null) { if (other.match != null) { return false; } } else if (!match.equals(other.match)) { return false; } if (outPort != other.outPort) { return false; } if (priority != other.priority) { return false; } return true; } /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override public OFFlowMod clone() throws CloneNotSupportedException { OFMatch neoMatch = match.clone(); OFFlowMod flowMod= (OFFlowMod) super.clone(); flowMod.setMatch(neoMatch); List neoActions = new LinkedList(); for(OFAction action: this.actions) neoActions.add((OFAction) action.clone()); flowMod.setActions(neoActions); return flowMod; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "OFFlowMod [actionFactory=" + actionFactory + ", actions=" + actions + ", bufferId=" + bufferId + ", command=" + command + ", cookie=" + cookie + ", flags=" + flags + ", hardTimeout=" + hardTimeout + ", idleTimeout=" + idleTimeout + ", match=" + match + ", outPort=" + outPort + ", priority=" + priority + ", length=" + length + ", type=" + type + ", version=" + version + ", xid=" + xid + "]"; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFMessageContextStore.java0000664000175000017500000000233512041336206030224 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.protocol.OFMessage; public class OFMessageContextStore { protected OFMessage msg; String namespace; public OFMessageContextStore(OFMessage msg, String namespace) { this.msg = msg; this.namespace = namespace; } @SuppressWarnings("unchecked") public V get(String key) { return (V)msg.getMessageStore().get(namespace + "|" + key); } public void put(String key, V value) { msg.getMessageStore().put(namespace + "|" + key, value); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java0000664000175000017500000001102612041336206030505 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.factory.OFStatisticsFactory; import org.openflow.protocol.factory.OFStatisticsFactoryAware; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; /** * Base class for statistics requests/replies * * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 27, 2010 */ public abstract class OFStatisticsMessageBase extends OFMessage implements OFStatisticsFactoryAware { public static int MINIMUM_LENGTH = 12; protected OFStatisticsFactory statisticsFactory; protected OFStatisticsType statisticType; protected short flags; protected List statistics; /** * @return the statisticType */ public OFStatisticsType getStatisticType() { return statisticType; } /** * @param statisticType the statisticType to set */ public void setStatisticType(OFStatisticsType statisticType) { this.statisticType = statisticType; } /** * @return the flags */ public short getFlags() { return flags; } /** * @param flags the flags to set */ public void setFlags(short flags) { this.flags = flags; } /** * @return the statistics */ public List getStatistics() { return statistics; } /** * @param statistics the statistics to set */ public void setStatistics(List statistics) { this.statistics = statistics; } @Override public void setStatisticsFactory(OFStatisticsFactory statisticsFactory) { this.statisticsFactory = statisticsFactory; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.statisticType = OFStatisticsType.valueOf(data.readShort(), this .getType()); this.flags = data.readShort(); if (this.statisticsFactory == null) throw new RuntimeException("OFStatisticsFactory not set"); this.statistics = statisticsFactory.parseStatistics(this.getType(), this.statisticType, data, super.getLengthU() - MINIMUM_LENGTH); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.statisticType.getTypeValue()); data.writeShort(this.flags); if (this.statistics != null) { for (OFStatistics statistic : this.statistics) { statistic.writeTo(data); } } } @Override public int hashCode() { final int prime = 317; int result = super.hashCode(); result = prime * result + flags; result = prime * result + ((statisticType == null) ? 0 : statisticType.hashCode()); result = prime * result + ((statistics == null) ? 0 : statistics.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFStatisticsMessageBase)) { return false; } OFStatisticsMessageBase other = (OFStatisticsMessageBase) obj; if (flags != other.flags) { return false; } if (statisticType == null) { if (other.statisticType != null) { return false; } } else if (!statisticType.equals(other.statisticType)) { return false; } if (statistics == null) { if (other.statistics != null) { return false; } } else if (!statistics.equals(other.statistics)) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFBarrierRequest.java0000664000175000017500000000204112041336206027207 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an OFPT_BARRIER_REQUEST message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFBarrierRequest extends OFMessage { public OFBarrierRequest() { super(); this.type = OFType.BARRIER_REQUEST; this.length = U16.t(OFMessage.MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFBarrierReply.java0000664000175000017500000000203112041336206026651 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an OFPT_BARRIER_REPLY message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFBarrierReply extends OFMessage { public OFBarrierReply() { super(); this.type = OFType.BARRIER_REPLY; this.length = U16.t(OFMessage.MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPortStatus.java0000664000175000017500000000616612041336206026414 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * Represents an ofp_port_status message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFPortStatus extends OFMessage { public static int MINIMUM_LENGTH = 64; public enum OFPortReason { OFPPR_ADD, OFPPR_DELETE, OFPPR_MODIFY } protected byte reason; protected OFPhysicalPort desc; /** * @return the reason */ public byte getReason() { return reason; } /** * @param reason the reason to set */ public void setReason(byte reason) { this.reason = reason; } /** * @return the desc */ public OFPhysicalPort getDesc() { return desc; } /** * @param desc the desc to set */ public void setDesc(OFPhysicalPort desc) { this.desc = desc; } public OFPortStatus() { super(); this.type = OFType.PORT_STATUS; this.length = U16.t(MINIMUM_LENGTH); } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.reason = data.readByte(); data.readerIndex(data.readerIndex() + 7); // skip 7 bytes of padding if (this.desc == null) this.desc = new OFPhysicalPort(); this.desc.readFrom(data); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeByte(this.reason); for (int i = 0; i < 7; ++i) data.writeByte((byte) 0); this.desc.writeTo(data); } @Override public int hashCode() { final int prime = 313; int result = super.hashCode(); result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + reason; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFPortStatus)) { return false; } OFPortStatus other = (OFPortStatus) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (reason != other.reason) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPortMod.java0000664000175000017500000001111712041336206025640 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * Represents an ofp_port_mod message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFPortMod extends OFMessage { public static int MINIMUM_LENGTH = 32; protected short portNumber; protected byte[] hardwareAddress; protected int config; protected int mask; protected int advertise; public OFPortMod() { super(); this.type = OFType.PORT_MOD; this.length = U16.t(MINIMUM_LENGTH); } /** * @return the portNumber */ public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } /** * @return the hardwareAddress */ public byte[] getHardwareAddress() { return hardwareAddress; } /** * @param hardwareAddress the hardwareAddress to set */ public void setHardwareAddress(byte[] hardwareAddress) { if (hardwareAddress.length != OFPhysicalPort.OFP_ETH_ALEN) throw new RuntimeException("Hardware address must have length " + OFPhysicalPort.OFP_ETH_ALEN); this.hardwareAddress = hardwareAddress; } /** * @return the config */ public int getConfig() { return config; } /** * @param config the config to set */ public void setConfig(int config) { this.config = config; } /** * @return the mask */ public int getMask() { return mask; } /** * @param mask the mask to set */ public void setMask(int mask) { this.mask = mask; } /** * @return the advertise */ public int getAdvertise() { return advertise; } /** * @param advertise the advertise to set */ public void setAdvertise(int advertise) { this.advertise = advertise; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.portNumber = data.readShort(); if (this.hardwareAddress == null) this.hardwareAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN]; data.readBytes(this.hardwareAddress); this.config = data.readInt(); this.mask = data.readInt(); this.advertise = data.readInt(); data.readInt(); // pad } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.portNumber); data.writeBytes(this.hardwareAddress); data.writeInt(this.config); data.writeInt(this.mask); data.writeInt(this.advertise); data.writeInt(0); // pad } @Override public int hashCode() { final int prime = 311; int result = super.hashCode(); result = prime * result + advertise; result = prime * result + config; result = prime * result + Arrays.hashCode(hardwareAddress); result = prime * result + mask; result = prime * result + portNumber; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFPortMod)) { return false; } OFPortMod other = (OFPortMod) obj; if (advertise != other.advertise) { return false; } if (config != other.config) { return false; } if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) { return false; } if (mask != other.mask) { return false; } if (portNumber != other.portNumber) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/0000775000175000017500000000000012041336206025355 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java0000664000175000017500000001103212041336206032615 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.codehaus.jackson.annotate.JsonIgnore; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_queue_stats structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFQueueStatisticsReply implements OFStatistics { protected short portNumber; protected int queueId; protected long transmitBytes; protected long transmitPackets; protected long transmitErrors; /** * @return the portNumber */ public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } /** * @return the queueId */ public int getQueueId() { return queueId; } /** * @param queueId the queueId to set */ public void setQueueId(int queueId) { this.queueId = queueId; } /** * @return the transmitBytes */ public long getTransmitBytes() { return transmitBytes; } /** * @param transmitBytes the transmitBytes to set */ public void setTransmitBytes(long transmitBytes) { this.transmitBytes = transmitBytes; } /** * @return the transmitPackets */ public long getTransmitPackets() { return transmitPackets; } /** * @param transmitPackets the transmitPackets to set */ public void setTransmitPackets(long transmitPackets) { this.transmitPackets = transmitPackets; } /** * @return the transmitErrors */ public long getTransmitErrors() { return transmitErrors; } /** * @param transmitErrors the transmitErrors to set */ public void setTransmitErrors(long transmitErrors) { this.transmitErrors = transmitErrors; } @Override @JsonIgnore public int getLength() { return 32; } @Override public void readFrom(ChannelBuffer data) { this.portNumber = data.readShort(); data.readShort(); // pad this.queueId = data.readInt(); this.transmitBytes = data.readLong(); this.transmitPackets = data.readLong(); this.transmitErrors = data.readLong(); } @Override public void writeTo(ChannelBuffer data) { data.writeShort(this.portNumber); data.writeShort((short) 0); // pad data.writeInt(this.queueId); data.writeLong(this.transmitBytes); data.writeLong(this.transmitPackets); data.writeLong(this.transmitErrors); } @Override public int hashCode() { final int prime = 439; int result = 1; result = prime * result + portNumber; result = prime * result + queueId; result = prime * result + (int) (transmitBytes ^ (transmitBytes >>> 32)); result = prime * result + (int) (transmitErrors ^ (transmitErrors >>> 32)); result = prime * result + (int) (transmitPackets ^ (transmitPackets >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFQueueStatisticsReply)) { return false; } OFQueueStatisticsReply other = (OFQueueStatisticsReply) obj; if (portNumber != other.portNumber) { return false; } if (queueId != other.queueId) { return false; } if (transmitBytes != other.transmitBytes) { return false; } if (transmitErrors != other.transmitErrors) { return false; } if (transmitPackets != other.transmitPackets) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java0000664000175000017500000000523012041336206033155 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_queue_stats_request structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFQueueStatisticsRequest implements OFStatistics { protected short portNumber; protected int queueId; /** * @return the portNumber */ public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } /** * @return the queueId */ public int getQueueId() { return queueId; } /** * @param queueId the queueId to set */ public void setQueueId(int queueId) { this.queueId = queueId; } @Override public int getLength() { return 8; } @Override public void readFrom(ChannelBuffer data) { this.portNumber = data.readShort(); data.readShort(); // pad this.queueId = data.readInt(); } @Override public void writeTo(ChannelBuffer data) { data.writeShort(this.portNumber); data.writeShort((short) 0); // pad data.writeInt(this.queueId); } @Override public int hashCode() { final int prime = 443; int result = 1; result = prime * result + portNumber; result = prime * result + queueId; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFQueueStatisticsRequest)) { return false; } OFQueueStatisticsRequest other = (OFQueueStatisticsRequest) obj; if (portNumber != other.portNumber) { return false; } if (queueId != other.queueId) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java0000664000175000017500000002257412041336206032455 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import java.util.List; import org.codehaus.jackson.annotate.JsonIgnore; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFMatch; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.factory.OFActionFactory; import org.openflow.protocol.factory.OFActionFactoryAware; import org.openflow.util.U16; /** * Represents an ofp_flow_stats structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFFlowStatisticsReply implements OFStatistics, OFActionFactoryAware { public static int MINIMUM_LENGTH = 88; protected OFActionFactory actionFactory; protected short length = (short) MINIMUM_LENGTH; protected byte tableId; protected OFMatch match; protected int durationSeconds; protected int durationNanoseconds; protected short priority; protected short idleTimeout; protected short hardTimeout; protected long cookie; protected long packetCount; protected long byteCount; protected List actions; /** * @return the tableId */ public byte getTableId() { return tableId; } /** * @param tableId the tableId to set */ public void setTableId(byte tableId) { this.tableId = tableId; } /** * @return the match */ public OFMatch getMatch() { return match; } /** * @param match the match to set */ public void setMatch(OFMatch match) { this.match = match; } /** * @return the durationSeconds */ public int getDurationSeconds() { return durationSeconds; } /** * @param durationSeconds the durationSeconds to set */ public void setDurationSeconds(int durationSeconds) { this.durationSeconds = durationSeconds; } /** * @return the durationNanoseconds */ public int getDurationNanoseconds() { return durationNanoseconds; } /** * @param durationNanoseconds the durationNanoseconds to set */ public void setDurationNanoseconds(int durationNanoseconds) { this.durationNanoseconds = durationNanoseconds; } /** * @return the priority */ public short getPriority() { return priority; } /** * @param priority the priority to set */ public void setPriority(short priority) { this.priority = priority; } /** * @return the idleTimeout */ public short getIdleTimeout() { return idleTimeout; } /** * @param idleTimeout the idleTimeout to set */ public void setIdleTimeout(short idleTimeout) { this.idleTimeout = idleTimeout; } /** * @return the hardTimeout */ public short getHardTimeout() { return hardTimeout; } /** * @param hardTimeout the hardTimeout to set */ public void setHardTimeout(short hardTimeout) { this.hardTimeout = hardTimeout; } /** * @return the cookie */ public long getCookie() { return cookie; } /** * @param cookie the cookie to set */ public void setCookie(long cookie) { this.cookie = cookie; } /** * @return the packetCount */ public long getPacketCount() { return packetCount; } /** * @param packetCount the packetCount to set */ public void setPacketCount(long packetCount) { this.packetCount = packetCount; } /** * @return the byteCount */ public long getByteCount() { return byteCount; } /** * @param byteCount the byteCount to set */ public void setByteCount(long byteCount) { this.byteCount = byteCount; } /** * @param length the length to set */ public void setLength(short length) { this.length = length; } @Override @JsonIgnore public int getLength() { return U16.f(length); } /** * @param actionFactory the actionFactory to set */ @Override public void setActionFactory(OFActionFactory actionFactory) { this.actionFactory = actionFactory; } /** * @return the actions */ public List getActions() { return actions; } /** * @param actions the actions to set */ public void setActions(List actions) { this.actions = actions; } @Override public void readFrom(ChannelBuffer data) { this.length = data.readShort(); this.tableId = data.readByte(); data.readByte(); // pad if (this.match == null) this.match = new OFMatch(); this.match.readFrom(data); this.durationSeconds = data.readInt(); this.durationNanoseconds = data.readInt(); this.priority = data.readShort(); this.idleTimeout = data.readShort(); this.hardTimeout = data.readShort(); data.readInt(); // pad data.readShort(); // pad this.cookie = data.readLong(); this.packetCount = data.readLong(); this.byteCount = data.readLong(); if (this.actionFactory == null) throw new RuntimeException("OFActionFactory not set"); this.actions = this.actionFactory.parseActions(data, getLength() - MINIMUM_LENGTH); } @Override public void writeTo(ChannelBuffer data) { data.writeShort(this.length); data.writeByte(this.tableId); data.writeByte((byte) 0); this.match.writeTo(data); data.writeInt(this.durationSeconds); data.writeInt(this.durationNanoseconds); data.writeShort(this.priority); data.writeShort(this.idleTimeout); data.writeShort(this.hardTimeout); data.writeInt(0); // pad data.writeShort((short)0); // pad data.writeLong(this.cookie); data.writeLong(this.packetCount); data.writeLong(this.byteCount); if (actions != null) { for (OFAction action : actions) { action.writeTo(data); } } } @Override public String toString() { String str = "match=" + this.match; str += " tableId=" + this.tableId; str += " durationSeconds=" + this.durationSeconds; str += " durationNanoseconds=" + this.durationNanoseconds; str += " priority=" + this.priority; str += " idleTimeout=" + this.idleTimeout; str += " hardTimeout=" + this.hardTimeout; str += " cookie=" + this.cookie; str += " packetCount=" + this.packetCount; str += " byteCount=" + this.byteCount; str += " action=" + this.actions; return str; } @Override public int hashCode() { final int prime = 419; int result = 1; result = prime * result + (int) (byteCount ^ (byteCount >>> 32)); result = prime * result + (int) (cookie ^ (cookie >>> 32)); result = prime * result + durationNanoseconds; result = prime * result + durationSeconds; result = prime * result + hardTimeout; result = prime * result + idleTimeout; result = prime * result + length; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + (int) (packetCount ^ (packetCount >>> 32)); result = prime * result + priority; result = prime * result + tableId; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFFlowStatisticsReply)) { return false; } OFFlowStatisticsReply other = (OFFlowStatisticsReply) obj; if (byteCount != other.byteCount) { return false; } if (cookie != other.cookie) { return false; } if (durationNanoseconds != other.durationNanoseconds) { return false; } if (durationSeconds != other.durationSeconds) { return false; } if (hardTimeout != other.hardTimeout) { return false; } if (idleTimeout != other.idleTimeout) { return false; } if (length != other.length) { return false; } if (match == null) { if (other.match != null) { return false; } } else if (!match.equals(other.match)) { return false; } if (packetCount != other.packetCount) { return false; } if (priority != other.priority) { return false; } if (tableId != other.tableId) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java0000664000175000017500000000645312041336206033010 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFMatch; /** * Represents an ofp_flow_stats_request structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFFlowStatisticsRequest implements OFStatistics { protected OFMatch match; protected byte tableId; protected short outPort; /** * @return the match */ public OFMatch getMatch() { return match; } /** * @param match the match to set */ public void setMatch(OFMatch match) { this.match = match; } /** * @return the tableId */ public byte getTableId() { return tableId; } /** * @param tableId the tableId to set */ public void setTableId(byte tableId) { this.tableId = tableId; } /** * @return the outPort */ public short getOutPort() { return outPort; } /** * @param outPort the outPort to set */ public void setOutPort(short outPort) { this.outPort = outPort; } @Override public int getLength() { return 44; } @Override public void readFrom(ChannelBuffer data) { if (this.match == null) this.match = new OFMatch(); this.match.readFrom(data); this.tableId = data.readByte(); data.readByte(); // pad this.outPort = data.readShort(); } @Override public void writeTo(ChannelBuffer data) { this.match.writeTo(data); data.writeByte(this.tableId); data.writeByte((byte) 0); data.writeShort(this.outPort); } @Override public int hashCode() { final int prime = 421; int result = 1; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + outPort; result = prime * result + tableId; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFFlowStatisticsRequest)) { return false; } OFFlowStatisticsRequest other = (OFFlowStatisticsRequest) obj; if (match == null) { if (other.match != null) { return false; } } else if (!match.equals(other.match)) { return false; } if (outPort != other.outPort) { return false; } if (tableId != other.tableId) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java0000664000175000017500000000650412041336206033764 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFMatch; /** * Represents an ofp_aggregate_stats_request structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFAggregateStatisticsRequest implements OFStatistics { protected OFMatch match; protected byte tableId; protected short outPort; /** * @return the match */ public OFMatch getMatch() { return match; } /** * @param match the match to set */ public void setMatch(OFMatch match) { this.match = match; } /** * @return the tableId */ public byte getTableId() { return tableId; } /** * @param tableId the tableId to set */ public void setTableId(byte tableId) { this.tableId = tableId; } /** * @return the outPort */ public short getOutPort() { return outPort; } /** * @param outPort the outPort to set */ public void setOutPort(short outPort) { this.outPort = outPort; } @Override public int getLength() { return 44; } @Override public void readFrom(ChannelBuffer data) { if (this.match == null) this.match = new OFMatch(); this.match.readFrom(data); this.tableId = data.readByte(); data.readByte(); // pad this.outPort = data.readShort(); } @Override public void writeTo(ChannelBuffer data) { this.match.writeTo(data); data.writeByte(this.tableId); data.writeByte((byte) 0); data.writeShort(this.outPort); } @Override public int hashCode() { final int prime = 401; int result = 1; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + outPort; result = prime * result + tableId; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFAggregateStatisticsRequest)) { return false; } OFAggregateStatisticsRequest other = (OFAggregateStatisticsRequest) obj; if (match == null) { if (other.match != null) { return false; } } else if (!match.equals(other.match)) { return false; } if (outPort != other.outPort) { return false; } if (tableId != other.tableId) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java0000664000175000017500000002326612041336206032471 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.codehaus.jackson.annotate.JsonIgnore; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_port_stats structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFPortStatisticsReply implements OFStatistics { protected short portNumber; protected long receivePackets; protected long transmitPackets; protected long receiveBytes; protected long transmitBytes; protected long receiveDropped; protected long transmitDropped; protected long receiveErrors; protected long transmitErrors; protected long receiveFrameErrors; protected long receiveOverrunErrors; protected long receiveCRCErrors; protected long collisions; /** * @return the portNumber */ public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } /** * @return the receivePackets */ public long getreceivePackets() { return receivePackets; } /** * @param receivePackets the receivePackets to set */ public void setreceivePackets(long receivePackets) { this.receivePackets = receivePackets; } /** * @return the transmitPackets */ public long getTransmitPackets() { return transmitPackets; } /** * @param transmitPackets the transmitPackets to set */ public void setTransmitPackets(long transmitPackets) { this.transmitPackets = transmitPackets; } /** * @return the receiveBytes */ public long getReceiveBytes() { return receiveBytes; } /** * @param receiveBytes the receiveBytes to set */ public void setReceiveBytes(long receiveBytes) { this.receiveBytes = receiveBytes; } /** * @return the transmitBytes */ public long getTransmitBytes() { return transmitBytes; } /** * @param transmitBytes the transmitBytes to set */ public void setTransmitBytes(long transmitBytes) { this.transmitBytes = transmitBytes; } /** * @return the receiveDropped */ public long getReceiveDropped() { return receiveDropped; } /** * @param receiveDropped the receiveDropped to set */ public void setReceiveDropped(long receiveDropped) { this.receiveDropped = receiveDropped; } /** * @return the transmitDropped */ public long getTransmitDropped() { return transmitDropped; } /** * @param transmitDropped the transmitDropped to set */ public void setTransmitDropped(long transmitDropped) { this.transmitDropped = transmitDropped; } /** * @return the receiveErrors */ public long getreceiveErrors() { return receiveErrors; } /** * @param receiveErrors the receiveErrors to set */ public void setreceiveErrors(long receiveErrors) { this.receiveErrors = receiveErrors; } /** * @return the transmitErrors */ public long getTransmitErrors() { return transmitErrors; } /** * @param transmitErrors the transmitErrors to set */ public void setTransmitErrors(long transmitErrors) { this.transmitErrors = transmitErrors; } /** * @return the receiveFrameErrors */ public long getReceiveFrameErrors() { return receiveFrameErrors; } /** * @param receiveFrameErrors the receiveFrameErrors to set */ public void setReceiveFrameErrors(long receiveFrameErrors) { this.receiveFrameErrors = receiveFrameErrors; } /** * @return the receiveOverrunErrors */ public long getReceiveOverrunErrors() { return receiveOverrunErrors; } /** * @param receiveOverrunErrors the receiveOverrunErrors to set */ public void setReceiveOverrunErrors(long receiveOverrunErrors) { this.receiveOverrunErrors = receiveOverrunErrors; } /** * @return the receiveCRCErrors */ public long getReceiveCRCErrors() { return receiveCRCErrors; } /** * @param receiveCRCErrors the receiveCRCErrors to set */ public void setReceiveCRCErrors(long receiveCRCErrors) { this.receiveCRCErrors = receiveCRCErrors; } /** * @return the collisions */ public long getCollisions() { return collisions; } /** * @param collisions the collisions to set */ public void setCollisions(long collisions) { this.collisions = collisions; } @Override @JsonIgnore public int getLength() { return 104; } @Override public void readFrom(ChannelBuffer data) { this.portNumber = data.readShort(); data.readShort(); // pad data.readInt(); // pad this.receivePackets = data.readLong(); this.transmitPackets = data.readLong(); this.receiveBytes = data.readLong(); this.transmitBytes = data.readLong(); this.receiveDropped = data.readLong(); this.transmitDropped = data.readLong(); this.receiveErrors = data.readLong(); this.transmitErrors = data.readLong(); this.receiveFrameErrors = data.readLong(); this.receiveOverrunErrors = data.readLong(); this.receiveCRCErrors = data.readLong(); this.collisions = data.readLong(); } @Override public void writeTo(ChannelBuffer data) { data.writeShort(this.portNumber); data.writeShort((short) 0); // pad data.writeInt(0); // pad data.writeLong(this.receivePackets); data.writeLong(this.transmitPackets); data.writeLong(this.receiveBytes); data.writeLong(this.transmitBytes); data.writeLong(this.receiveDropped); data.writeLong(this.transmitDropped); data.writeLong(this.receiveErrors); data.writeLong(this.transmitErrors); data.writeLong(this.receiveFrameErrors); data.writeLong(this.receiveOverrunErrors); data.writeLong(this.receiveCRCErrors); data.writeLong(this.collisions); } @Override public int hashCode() { final int prime = 431; int result = 1; result = prime * result + (int) (collisions ^ (collisions >>> 32)); result = prime * result + portNumber; result = prime * result + (int) (receivePackets ^ (receivePackets >>> 32)); result = prime * result + (int) (receiveBytes ^ (receiveBytes >>> 32)); result = prime * result + (int) (receiveCRCErrors ^ (receiveCRCErrors >>> 32)); result = prime * result + (int) (receiveDropped ^ (receiveDropped >>> 32)); result = prime * result + (int) (receiveFrameErrors ^ (receiveFrameErrors >>> 32)); result = prime * result + (int) (receiveOverrunErrors ^ (receiveOverrunErrors >>> 32)); result = prime * result + (int) (receiveErrors ^ (receiveErrors >>> 32)); result = prime * result + (int) (transmitBytes ^ (transmitBytes >>> 32)); result = prime * result + (int) (transmitDropped ^ (transmitDropped >>> 32)); result = prime * result + (int) (transmitErrors ^ (transmitErrors >>> 32)); result = prime * result + (int) (transmitPackets ^ (transmitPackets >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFPortStatisticsReply)) { return false; } OFPortStatisticsReply other = (OFPortStatisticsReply) obj; if (collisions != other.collisions) { return false; } if (portNumber != other.portNumber) { return false; } if (receivePackets != other.receivePackets) { return false; } if (receiveBytes != other.receiveBytes) { return false; } if (receiveCRCErrors != other.receiveCRCErrors) { return false; } if (receiveDropped != other.receiveDropped) { return false; } if (receiveFrameErrors != other.receiveFrameErrors) { return false; } if (receiveOverrunErrors != other.receiveOverrunErrors) { return false; } if (receiveErrors != other.receiveErrors) { return false; } if (transmitBytes != other.transmitBytes) { return false; } if (transmitDropped != other.transmitDropped) { return false; } if (transmitErrors != other.transmitErrors) { return false; } if (transmitPackets != other.transmitPackets) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java0000664000175000017500000001537212041336206033013 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.StringByteSerializer; /** * Represents an ofp_desc_stats structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFDescriptionStatistics implements OFStatistics { public static int DESCRIPTION_STRING_LENGTH = 256; public static int SERIAL_NUMBER_LENGTH = 32; protected String manufacturerDescription; protected String hardwareDescription; protected String softwareDescription; protected String serialNumber; protected String datapathDescription; /** * @return the manufacturerDescription */ public String getManufacturerDescription() { return manufacturerDescription; } /** * @param manufacturerDescription the manufacturerDescription to set */ public void setManufacturerDescription(String manufacturerDescription) { this.manufacturerDescription = manufacturerDescription; } /** * @return the hardwareDescription */ public String getHardwareDescription() { return hardwareDescription; } /** * @param hardwareDescription the hardwareDescription to set */ public void setHardwareDescription(String hardwareDescription) { this.hardwareDescription = hardwareDescription; } /** * @return the softwareDescription */ public String getSoftwareDescription() { return softwareDescription; } /** * @param softwareDescription the softwareDescription to set */ public void setSoftwareDescription(String softwareDescription) { this.softwareDescription = softwareDescription; } /** * @return the serialNumber */ public String getSerialNumber() { return serialNumber; } /** * @param serialNumber the serialNumber to set */ public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } /** * @return the datapathDescription */ public String getDatapathDescription() { return datapathDescription; } /** * @param datapathDescription the datapathDescription to set */ public void setDatapathDescription(String datapathDescription) { this.datapathDescription = datapathDescription; } @Override public int getLength() { return 1056; } @Override public void readFrom(ChannelBuffer data) { this.manufacturerDescription = StringByteSerializer.readFrom(data, DESCRIPTION_STRING_LENGTH); this.hardwareDescription = StringByteSerializer.readFrom(data, DESCRIPTION_STRING_LENGTH); this.softwareDescription = StringByteSerializer.readFrom(data, DESCRIPTION_STRING_LENGTH); this.serialNumber = StringByteSerializer.readFrom(data, SERIAL_NUMBER_LENGTH); this.datapathDescription = StringByteSerializer.readFrom(data, DESCRIPTION_STRING_LENGTH); } @Override public void writeTo(ChannelBuffer data) { StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH, this.manufacturerDescription); StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH, this.hardwareDescription); StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH, this.softwareDescription); StringByteSerializer.writeTo(data, SERIAL_NUMBER_LENGTH, this.serialNumber); StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH, this.datapathDescription); } @Override public int hashCode() { final int prime = 409; int result = 1; result = prime * result + ((datapathDescription == null) ? 0 : datapathDescription .hashCode()); result = prime * result + ((hardwareDescription == null) ? 0 : hardwareDescription .hashCode()); result = prime * result + ((manufacturerDescription == null) ? 0 : manufacturerDescription.hashCode()); result = prime * result + ((serialNumber == null) ? 0 : serialNumber.hashCode()); result = prime * result + ((softwareDescription == null) ? 0 : softwareDescription .hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFDescriptionStatistics)) { return false; } OFDescriptionStatistics other = (OFDescriptionStatistics) obj; if (datapathDescription == null) { if (other.datapathDescription != null) { return false; } } else if (!datapathDescription.equals(other.datapathDescription)) { return false; } if (hardwareDescription == null) { if (other.hardwareDescription != null) { return false; } } else if (!hardwareDescription.equals(other.hardwareDescription)) { return false; } if (manufacturerDescription == null) { if (other.manufacturerDescription != null) { return false; } } else if (!manufacturerDescription .equals(other.manufacturerDescription)) { return false; } if (serialNumber == null) { if (other.serialNumber != null) { return false; } } else if (!serialNumber.equals(other.serialNumber)) { return false; } if (softwareDescription == null) { if (other.softwareDescription != null) { return false; } } else if (!softwareDescription.equals(other.softwareDescription)) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java0000664000175000017500000000440312041336206033016 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_port_stats_request structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFPortStatisticsRequest implements OFStatistics { protected short portNumber; /** * @return the portNumber */ public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } @Override public int getLength() { return 8; } @Override public void readFrom(ChannelBuffer data) { this.portNumber = data.readShort(); data.readShort(); // pad data.readInt(); // pad } @Override public void writeTo(ChannelBuffer data) { data.writeShort(this.portNumber); data.writeShort((short) 0); // pad data.writeInt(0); // pad } @Override public int hashCode() { final int prime = 433; int result = 1; result = prime * result + portNumber; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFPortStatisticsRequest)) { return false; } OFPortStatisticsRequest other = (OFPortStatisticsRequest) obj; if (portNumber != other.portNumber) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java0000664000175000017500000000645712041336206033436 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.codehaus.jackson.annotate.JsonIgnore; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_aggregate_stats_reply structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFAggregateStatisticsReply implements OFStatistics { protected long packetCount; protected long byteCount; protected int flowCount; /** * @return the packetCount */ public long getPacketCount() { return packetCount; } /** * @param packetCount the packetCount to set */ public void setPacketCount(long packetCount) { this.packetCount = packetCount; } /** * @return the byteCount */ public long getByteCount() { return byteCount; } /** * @param byteCount the byteCount to set */ public void setByteCount(long byteCount) { this.byteCount = byteCount; } /** * @return the flowCount */ public int getFlowCount() { return flowCount; } /** * @param flowCount the flowCount to set */ public void setFlowCount(int flowCount) { this.flowCount = flowCount; } @Override @JsonIgnore public int getLength() { return 24; } @Override public void readFrom(ChannelBuffer data) { this.packetCount = data.readLong(); this.byteCount = data.readLong(); this.flowCount = data.readInt(); data.readInt(); // pad } @Override public void writeTo(ChannelBuffer data) { data.writeLong(this.packetCount); data.writeLong(this.byteCount); data.writeInt(this.flowCount); data.writeInt(0); // pad } @Override public int hashCode() { final int prime = 397; int result = 1; result = prime * result + (int) (byteCount ^ (byteCount >>> 32)); result = prime * result + flowCount; result = prime * result + (int) (packetCount ^ (packetCount >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFAggregateStatisticsReply)) { return false; } OFAggregateStatisticsReply other = (OFAggregateStatisticsReply) obj; if (byteCount != other.byteCount) { return false; } if (flowCount != other.flowCount) { return false; } if (packetCount != other.packetCount) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFStatistics.java0000664000175000017500000000251512041336206030602 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; /** * The base class for all OpenFlow statistics. * * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public interface OFStatistics { /** * Returns the wire length of this message in bytes * @return the length */ public int getLength(); /** * Read this message off the wire from the specified ByteBuffer * @param data */ public void readFrom(ChannelBuffer data); /** * Write this message's binary format to the specified ByteBuffer * @param data */ public void writeTo(ChannelBuffer data); } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java0000664000175000017500000002746612041336206031460 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import java.lang.reflect.Constructor; import org.openflow.protocol.Instantiable; import org.openflow.protocol.OFType; public enum OFStatisticsType { DESC (0, OFDescriptionStatistics.class, OFDescriptionStatistics.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFDescriptionStatistics(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFDescriptionStatistics(); } }), FLOW (1, OFFlowStatisticsRequest.class, OFFlowStatisticsReply.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFFlowStatisticsRequest(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFFlowStatisticsReply(); } }), AGGREGATE (2, OFAggregateStatisticsRequest.class, OFAggregateStatisticsReply.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFAggregateStatisticsRequest(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFAggregateStatisticsReply(); } }), TABLE (3, OFTableStatistics.class, OFTableStatistics.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFTableStatistics(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFTableStatistics(); } }), PORT (4, OFPortStatisticsRequest.class, OFPortStatisticsReply.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFPortStatisticsRequest(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFPortStatisticsReply(); } }), QUEUE (5, OFQueueStatisticsRequest.class, OFQueueStatisticsReply.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFQueueStatisticsRequest(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFQueueStatisticsReply(); } }), VENDOR (0xffff, OFVendorStatistics.class, OFVendorStatistics.class, new Instantiable() { @Override public OFStatistics instantiate() { return new OFVendorStatistics(); } }, new Instantiable() { @Override public OFStatistics instantiate() { return new OFVendorStatistics(); } }); static OFStatisticsType[] requestMapping; static OFStatisticsType[] replyMapping; protected Class requestClass; protected Constructor requestConstructor; protected Instantiable requestInstantiable; protected Class replyClass; protected Constructor replyConstructor; protected Instantiable replyInstantiable; protected short type; /** * Store some information about the OpenFlow Statistic type, including wire * protocol type number, and derived class * * @param type Wire protocol number associated with this OFStatisticsType * @param requestClass The Statistics Java class to return when the * containing OFType is STATS_REQUEST * @param replyClass The Statistics Java class to return when the * containing OFType is STATS_REPLY */ OFStatisticsType(int type, Class requestClass, Class replyClass, Instantiable requestInstantiable, Instantiable replyInstantiable) { this.type = (short) type; this.requestClass = requestClass; try { this.requestConstructor = requestClass.getConstructor(new Class[]{}); } catch (Exception e) { throw new RuntimeException( "Failure getting constructor for class: " + requestClass, e); } this.replyClass = replyClass; try { this.replyConstructor = replyClass.getConstructor(new Class[]{}); } catch (Exception e) { throw new RuntimeException( "Failure getting constructor for class: " + replyClass, e); } this.requestInstantiable = requestInstantiable; this.replyInstantiable = replyInstantiable; OFStatisticsType.addMapping(this.type, OFType.STATS_REQUEST, this); OFStatisticsType.addMapping(this.type, OFType.STATS_REPLY, this); } /** * Adds a mapping from type value to OFStatisticsType enum * * @param i OpenFlow wire protocol type * @param t type of containing OFMessage, only accepts STATS_REQUEST or * STATS_REPLY * @param st type */ static public void addMapping(short i, OFType t, OFStatisticsType st) { if (i < 0) i = (short) (16+i); if (t == OFType.STATS_REQUEST) { if (requestMapping == null) requestMapping = new OFStatisticsType[16]; OFStatisticsType.requestMapping[i] = st; } else if (t == OFType.STATS_REPLY){ if (replyMapping == null) replyMapping = new OFStatisticsType[16]; OFStatisticsType.replyMapping[i] = st; } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } /** * Remove a mapping from type value to OFStatisticsType enum * * @param i OpenFlow wire protocol type * @param t type of containing OFMessage, only accepts STATS_REQUEST or * STATS_REPLY */ static public void removeMapping(short i, OFType t) { if (i < 0) i = (short) (16+i); if (t == OFType.STATS_REQUEST) { requestMapping[i] = null; } else if (t == OFType.STATS_REPLY){ replyMapping[i] = null; } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } /** * Given a wire protocol OpenFlow type number, return the OFStatisticsType * associated with it * * @param i wire protocol number * @param t type of containing OFMessage, only accepts STATS_REQUEST or * STATS_REPLY * @return OFStatisticsType enum type */ static public OFStatisticsType valueOf(short i, OFType t) { if (i < 0) i = (short) (16+i); if (t == OFType.STATS_REQUEST) { return requestMapping[i]; } else if (t == OFType.STATS_REPLY){ return replyMapping[i]; } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } /** * @return Returns the wire protocol value corresponding to this * OFStatisticsType */ public short getTypeValue() { return this.type; } /** * @param t type of containing OFMessage, only accepts STATS_REQUEST or * STATS_REPLY * @return return the OFMessage subclass corresponding to this * OFStatisticsType */ public Class toClass(OFType t) { if (t == OFType.STATS_REQUEST) { return requestClass; } else if (t == OFType.STATS_REPLY){ return replyClass; } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } /** * Returns the no-argument Constructor of the implementation class for * this OFStatisticsType, either request or reply based on the supplied * OFType * * @param t * @return */ public Constructor getConstructor(OFType t) { if (t == OFType.STATS_REQUEST) { return requestConstructor; } else if (t == OFType.STATS_REPLY) { return replyConstructor; } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } /** * @return the requestInstantiable */ public Instantiable getRequestInstantiable() { return requestInstantiable; } /** * @param requestInstantiable the requestInstantiable to set */ public void setRequestInstantiable( Instantiable requestInstantiable) { this.requestInstantiable = requestInstantiable; } /** * @return the replyInstantiable */ public Instantiable getReplyInstantiable() { return replyInstantiable; } /** * @param replyInstantiable the replyInstantiable to set */ public void setReplyInstantiable(Instantiable replyInstantiable) { this.replyInstantiable = replyInstantiable; } /** * Returns a new instance of the implementation class for * this OFStatisticsType, either request or reply based on the supplied * OFType * * @param t * @return */ public OFStatistics newInstance(OFType t) { if (t == OFType.STATS_REQUEST) { return requestInstantiable.instantiate(); } else if (t == OFType.STATS_REPLY) { return replyInstantiable.instantiate(); } else { throw new RuntimeException(t.toString() + " is an invalid OFType"); } } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java0000664000175000017500000001323712041336206031555 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.StringByteSerializer; /** * Represents an ofp_table_stats structure * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFTableStatistics implements OFStatistics { public static int MAX_TABLE_NAME_LEN = 32; protected byte tableId; protected String name; protected int wildcards; protected int maximumEntries; protected int activeCount; protected long lookupCount; protected long matchedCount; /** * @return the tableId */ public byte getTableId() { return tableId; } /** * @param tableId the tableId to set */ public void setTableId(byte tableId) { this.tableId = tableId; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the wildcards */ public int getWildcards() { return wildcards; } /** * @param wildcards the wildcards to set */ public void setWildcards(int wildcards) { this.wildcards = wildcards; } /** * @return the maximumEntries */ public int getMaximumEntries() { return maximumEntries; } /** * @param maximumEntries the maximumEntries to set */ public void setMaximumEntries(int maximumEntries) { this.maximumEntries = maximumEntries; } /** * @return the activeCount */ public int getActiveCount() { return activeCount; } /** * @param activeCount the activeCount to set */ public void setActiveCount(int activeCount) { this.activeCount = activeCount; } /** * @return the lookupCount */ public long getLookupCount() { return lookupCount; } /** * @param lookupCount the lookupCount to set */ public void setLookupCount(long lookupCount) { this.lookupCount = lookupCount; } /** * @return the matchedCount */ public long getMatchedCount() { return matchedCount; } /** * @param matchedCount the matchedCount to set */ public void setMatchedCount(long matchedCount) { this.matchedCount = matchedCount; } @Override public int getLength() { return 64; } @Override public void readFrom(ChannelBuffer data) { this.tableId = data.readByte(); data.readByte(); // pad data.readByte(); // pad data.readByte(); // pad this.name = StringByteSerializer.readFrom(data, MAX_TABLE_NAME_LEN); this.wildcards = data.readInt(); this.maximumEntries = data.readInt(); this.activeCount = data.readInt(); this.lookupCount = data.readLong(); this.matchedCount = data.readLong(); } @Override public void writeTo(ChannelBuffer data) { data.writeByte(this.tableId); data.writeByte((byte) 0); // pad data.writeByte((byte) 0); // pad data.writeByte((byte) 0); // pad StringByteSerializer.writeTo(data, MAX_TABLE_NAME_LEN, this.name); data.writeInt(this.wildcards); data.writeInt(this.maximumEntries); data.writeInt(this.activeCount); data.writeLong(this.lookupCount); data.writeLong(this.matchedCount); } @Override public int hashCode() { final int prime = 449; int result = 1; result = prime * result + activeCount; result = prime * result + (int) (lookupCount ^ (lookupCount >>> 32)); result = prime * result + (int) (matchedCount ^ (matchedCount >>> 32)); result = prime * result + maximumEntries; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + tableId; result = prime * result + wildcards; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFTableStatistics)) { return false; } OFTableStatistics other = (OFTableStatistics) obj; if (activeCount != other.activeCount) { return false; } if (lookupCount != other.lookupCount) { return false; } if (matchedCount != other.matchedCount) { return false; } if (maximumEntries != other.maximumEntries) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (tableId != other.tableId) { return false; } if (wildcards != other.wildcards) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java0000664000175000017500000000417212041336206031761 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.statistics; import org.jboss.netty.buffer.ChannelBuffer; /** * The base class for vendor implemented statistics * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFVendorStatistics implements OFStatistics { protected int vendor; protected byte[] body; // non-message fields protected int length = 0; @Override public void readFrom(ChannelBuffer data) { this.vendor = data.readInt(); if (body == null) body = new byte[length - 4]; data.readBytes(body); } @Override public void writeTo(ChannelBuffer data) { data.writeInt(this.vendor); if (body != null) data.writeBytes(body); } @Override public int hashCode() { final int prime = 457; int result = 1; result = prime * result + vendor; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFVendorStatistics)) { return false; } OFVendorStatistics other = (OFVendorStatistics) obj; if (vendor != other.vendor) { return false; } return true; } @Override public int getLength() { return length; } public void setLength(int length) { this.length = length; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFGetConfigReply.java0000664000175000017500000000172712041336206027143 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; /** * Represents an OFPT_GET_CONFIG_REPLY type message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFGetConfigReply extends OFSwitchConfig { public OFGetConfigReply() { super(); this.type = OFType.GET_CONFIG_REPLY; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFMessage.java0000664000175000017500000002244612041336206025647 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.packet.Ethernet; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.HexString; import org.openflow.util.U16; import org.openflow.util.U32; import org.openflow.util.U8; /** * The base class for all OpenFlow protocol messages. This class contains the * equivalent of the ofp_header which is present in all OpenFlow messages. * * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 3, 2010 * @author Rob Sherwood (rob.sherwood@stanford.edu) - Feb 3, 2010 */ public class OFMessage { public static byte OFP_VERSION = 0x01; public static int MINIMUM_LENGTH = 8; protected byte version; protected OFType type; protected short length; protected int xid; private ConcurrentHashMap storage; public OFMessage() { storage = null; this.version = OFP_VERSION; } protected synchronized ConcurrentHashMap getMessageStore() { if (storage == null) { storage = new ConcurrentHashMap();; } return storage; } /** * Get the length of this message * * @return */ public short getLength() { return length; } /** * Get the length of this message, unsigned * * @return */ public int getLengthU() { return U16.f(length); } /** * Set the length of this message * * @param length */ public OFMessage setLength(short length) { this.length = length; return this; } /** * Set the length of this message, unsigned * * @param length */ public OFMessage setLengthU(int length) { this.length = U16.t(length); return this; } /** * Get the type of this message * * @return */ public OFType getType() { return type; } /** * Set the type of this message * * @param type */ public void setType(OFType type) { this.type = type; } /** * Get the OpenFlow version of this message * * @return */ public byte getVersion() { return version; } /** * Set the OpenFlow version of this message * * @param version */ public void setVersion(byte version) { this.version = version; } /** * Get the transaction id of this message * * @return */ public int getXid() { return xid; } /** * Set the transaction id of this message * * @param xid */ public void setXid(int xid) { this.xid = xid; } /** * Read this message off the wire from the specified ByteBuffer * @param data */ public void readFrom(ChannelBuffer data) { this.version = data.readByte(); this.type = OFType.valueOf(data.readByte()); this.length = data.readShort(); this.xid = data.readInt(); } /** * Write this message's binary format to the specified ByteBuffer * @param data */ public void writeTo(ChannelBuffer data) { data.writeByte(version); data.writeByte(type.getTypeValue()); data.writeShort(length); data.writeInt(xid); } /** * Returns a summary of the message * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid" */ public String toString() { return "ofmsg" + ":v=" + U8.f(this.getVersion()) + ";t=" + this.getType() + ";l=" + this.getLengthU() + ";x=" + U32.f(this.getXid()); } @Override public int hashCode() { final int prime = 97; int result = 1; result = prime * result + length; result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + version; result = prime * result + xid; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFMessage)) { return false; } OFMessage other = (OFMessage) obj; if (length != other.length) { return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } if (version != other.version) { return false; } if (xid != other.xid) { return false; } return true; } public static String getDataAsString(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { Ethernet eth; StringBuffer sb = new StringBuffer(""); DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS"); Date date = new Date(); sb.append(dateFormat.format(date)); sb.append(" "); switch (msg.getType()) { case PACKET_IN: OFPacketIn pktIn = (OFPacketIn) msg; sb.append("packet_in [ "); sb.append(sw.getStringId()); sb.append(" -> Controller"); sb.append(" ]"); sb.append("\ntotal length: "); sb.append(pktIn.getTotalLength()); sb.append("\nin_port: "); sb.append(pktIn.getInPort()); sb.append("\ndata_length: "); sb.append(pktIn.getTotalLength() - OFPacketIn.MINIMUM_LENGTH); sb.append("\nbuffer: "); sb.append(pktIn.getBufferId()); // If the conext is not set by floodlight, then ignore. if (cntx != null) { // packet type icmp, arp, etc. eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); if (eth != null) sb.append(eth.toString()); } break; case PACKET_OUT: OFPacketOut pktOut = (OFPacketOut) msg; sb.append("packet_out [ "); sb.append("Controller -> "); sb.append(HexString.toHexString(sw.getId())); sb.append(" ]"); sb.append("\nin_port: "); sb.append(pktOut.getInPort()); sb.append("\nactions_len: "); sb.append(pktOut.getActionsLength()); if (pktOut.getActions() != null) { sb.append("\nactions: "); sb.append(pktOut.getActions().toString()); } break; case FLOW_MOD: OFFlowMod fm = (OFFlowMod) msg; sb.append("flow_mod [ "); sb.append("Controller -> "); sb.append(HexString.toHexString(sw.getId())); sb.append(" ]"); // If the conext is not set by floodlight, then ignore. if (cntx != null) { eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); if (eth != null) sb.append(eth.toString()); } sb.append("\nADD: cookie: "); sb.append(fm.getCookie()); sb.append(" idle: "); sb.append(fm.getIdleTimeout()); sb.append(" hard: "); sb.append(fm.getHardTimeout()); sb.append(" pri: "); sb.append(fm.getPriority()); sb.append(" buf: "); sb.append(fm.getBufferId()); sb.append(" flg: "); sb.append(fm.getFlags()); if (fm.getActions() != null) { sb.append("\nactions: "); sb.append(fm.getActions().toString()); } break; default: sb.append("[Unknown Packet]"); } sb.append("\n\n"); return sb.toString(); } public static byte[] getData(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { return OFMessage.getDataAsString(sw, msg, cntx).getBytes(); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFHello.java0000664000175000017500000000214212041336206025315 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an ofp_hello message * * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010 */ public class OFHello extends OFMessage { public static int MINIMUM_LENGTH = 8; /** * Construct a ofp_hello message */ public OFHello() { super(); this.type = OFType.HELLO; this.length = U16.t(MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPhysicalPort.java0000664000175000017500000003043712041336206026703 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Arrays; import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer; import net.floodlightcontroller.core.web.serializers.UShortSerializer; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents ofp_phy_port * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 25, 2010 */ public class OFPhysicalPort { public static int MINIMUM_LENGTH = 48; public static int OFP_ETH_ALEN = 6; public enum OFPortConfig { OFPPC_PORT_DOWN (1 << 0) { public String toString() { return "port-down (0x1)"; } }, OFPPC_NO_STP (1 << 1) { public String toString() { return "no-stp (0x2)"; } }, OFPPC_NO_RECV (1 << 2) { public String toString() { return "no-recv (0x4)"; } }, OFPPC_NO_RECV_STP (1 << 3) { public String toString() { return "no-recv-stp (0x8)"; } }, OFPPC_NO_FLOOD (1 << 4) { public String toString() { return "no-flood (0x10)"; } }, OFPPC_NO_FWD (1 << 5) { public String toString() { return "no-fwd (0x20)"; } }, OFPPC_NO_PACKET_IN (1 << 6) { public String toString() { return "no-pkt-in (0x40)"; } }; protected int value; private OFPortConfig(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } } public enum OFPortState { OFPPS_LINK_DOWN (1 << 0) { public String toString() { return "link-down (0x1)"; } }, OFPPS_STP_LISTEN (0 << 8) { public String toString() { return "listen (0x0)"; } }, OFPPS_STP_LEARN (1 << 8) { public String toString() { return "learn-no-relay (0x100)"; } }, OFPPS_STP_FORWARD (2 << 8) { public String toString() { return "forward (0x200)"; } }, OFPPS_STP_BLOCK (3 << 8) { public String toString() { return "block-broadcast (0x300)"; } }, OFPPS_STP_MASK (3 << 8) { public String toString() { return "block-broadcast (0x300)"; } }; protected int value; private OFPortState(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } } public enum OFPortFeatures { OFPPF_10MB_HD (1 << 0) { public String toString() { return "10mb-hd (0x1)"; } }, OFPPF_10MB_FD (1 << 1) { public String toString() { return "10mb-fd (0x2)"; } }, OFPPF_100MB_HD (1 << 2) { public String toString() { return "100mb-hd (0x4)"; } }, OFPPF_100MB_FD (1 << 3) { public String toString() { return "100mb-fd (0x8)"; } }, OFPPF_1GB_HD (1 << 4) { public String toString() { return "1gb-hd (0x10)"; } }, OFPPF_1GB_FD (1 << 5) { public String toString() { return "1gb-fd (0x20)"; } }, OFPPF_10GB_FD (1 << 6) { public String toString() { return "10gb-fd (0x40)"; } }, OFPPF_COPPER (1 << 7) { public String toString() { return "copper (0x80)"; } }, OFPPF_FIBER (1 << 8) { public String toString() { return "fiber (0x100)"; } }, OFPPF_AUTONEG (1 << 9) { public String toString() { return "autoneg (0x200)"; } }, OFPPF_PAUSE (1 << 10) { public String toString() { return "pause (0x400)"; } }, OFPPF_PAUSE_ASYM (1 << 11) { public String toString() { return "pause-asym (0x800)"; } }; protected int value; private OFPortFeatures(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } } protected short portNumber; protected byte[] hardwareAddress; protected String name; protected int config; protected int state; protected int currentFeatures; protected int advertisedFeatures; protected int supportedFeatures; protected int peerFeatures; /** * @return the portNumber */ @JsonSerialize(using=UShortSerializer.class) public short getPortNumber() { return portNumber; } /** * @param portNumber the portNumber to set */ public void setPortNumber(short portNumber) { this.portNumber = portNumber; } /** * @return the hardwareAddress */ @JsonSerialize(using=ByteArrayMACSerializer.class) public byte[] getHardwareAddress() { return hardwareAddress; } /** * @param hardwareAddress the hardwareAddress to set */ public void setHardwareAddress(byte[] hardwareAddress) { if (hardwareAddress.length != OFP_ETH_ALEN) throw new RuntimeException("Hardware address must have length " + OFP_ETH_ALEN); this.hardwareAddress = hardwareAddress; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the config */ public int getConfig() { return config; } /** * @param config the config to set */ public void setConfig(int config) { this.config = config; } /** * @return the state */ public int getState() { return state; } /** * @param state the state to set */ public void setState(int state) { this.state = state; } /** * @return the currentFeatures */ public int getCurrentFeatures() { return currentFeatures; } /** * @param currentFeatures the currentFeatures to set */ public void setCurrentFeatures(int currentFeatures) { this.currentFeatures = currentFeatures; } /** * @return the advertisedFeatures */ public int getAdvertisedFeatures() { return advertisedFeatures; } /** * @param advertisedFeatures the advertisedFeatures to set */ public void setAdvertisedFeatures(int advertisedFeatures) { this.advertisedFeatures = advertisedFeatures; } /** * @return the supportedFeatures */ public int getSupportedFeatures() { return supportedFeatures; } /** * @param supportedFeatures the supportedFeatures to set */ public void setSupportedFeatures(int supportedFeatures) { this.supportedFeatures = supportedFeatures; } /** * @return the peerFeatures */ public int getPeerFeatures() { return peerFeatures; } /** * @param peerFeatures the peerFeatures to set */ public void setPeerFeatures(int peerFeatures) { this.peerFeatures = peerFeatures; } /** * Read this message off the wire from the specified ByteBuffer * @param data */ public void readFrom(ChannelBuffer data) { this.portNumber = data.readShort(); if (this.hardwareAddress == null) this.hardwareAddress = new byte[OFP_ETH_ALEN]; data.readBytes(this.hardwareAddress); byte[] name = new byte[16]; data.readBytes(name); // find the first index of 0 int index = 0; for (byte b : name) { if (0 == b) break; ++index; } this.name = new String(Arrays.copyOf(name, index), Charset.forName("ascii")); this.config = data.readInt(); this.state = data.readInt(); this.currentFeatures = data.readInt(); this.advertisedFeatures = data.readInt(); this.supportedFeatures = data.readInt(); this.peerFeatures = data.readInt(); } /** * Write this message's binary format to the specified ByteBuffer * @param data */ public void writeTo(ChannelBuffer data) { data.writeShort(this.portNumber); data.writeBytes(hardwareAddress); try { byte[] name = this.name.getBytes("ASCII"); if (name.length < 16) { data.writeBytes(name); for (int i = name.length; i < 16; ++i) { data.writeByte((byte) 0); } } else { data.writeBytes(name, 0, 15); data.writeByte((byte) 0); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } data.writeInt(this.config); data.writeInt(this.state); data.writeInt(this.currentFeatures); data.writeInt(this.advertisedFeatures); data.writeInt(this.supportedFeatures); data.writeInt(this.peerFeatures); } @Override public int hashCode() { final int prime = 307; int result = 1; result = prime * result + advertisedFeatures; result = prime * result + config; result = prime * result + currentFeatures; result = prime * result + Arrays.hashCode(hardwareAddress); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + peerFeatures; result = prime * result + portNumber; result = prime * result + state; result = prime * result + supportedFeatures; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFPhysicalPort)) { return false; } OFPhysicalPort other = (OFPhysicalPort) obj; if (advertisedFeatures != other.advertisedFeatures) { return false; } if (config != other.config) { return false; } if (currentFeatures != other.currentFeatures) { return false; } if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (peerFeatures != other.peerFeatures) { return false; } if (portNumber != other.portNumber) { return false; } if (state != other.state) { return false; } if (supportedFeatures != other.supportedFeatures) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/serializers/0000775000175000017500000000000012041336206025517 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/serializers/OFMatchJSONSerializer.java0000664000175000017500000000724412041336206032376 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.protocol.OFMatch; import org.openflow.util.HexString; public class OFMatchJSONSerializer extends JsonSerializer { /** * Converts an IP in a 32 bit integer to a dotted-decimal string * @param i The IP address in a 32 bit integer * @return An IP address string in dotted-decimal */ private String intToIp(int i) { return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >> 8 ) & 0xFF) + "." + ( i & 0xFF); } /** * Performs the serialization of a OFMatch object */ @Override public void serialize(OFMatch match, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); jGen.writeStringField("dataLayerDestination", HexString.toHexString(match.getDataLayerDestination())); jGen.writeStringField("dataLayerSource", HexString.toHexString(match.getDataLayerSource())); String dataType = Integer.toHexString(match.getDataLayerType()); while (dataType.length() < 4) { dataType = "0".concat(dataType); } jGen.writeStringField("dataLayerType", "0x" + dataType); jGen.writeNumberField("dataLayerVirtualLan", match.getDataLayerVirtualLan()); jGen.writeNumberField("dataLayerVirtualLanPriorityCodePoint", match.getDataLayerVirtualLanPriorityCodePoint()); jGen.writeNumberField("inputPort", match.getInputPort()); jGen.writeStringField("networkDestination", intToIp(match.getNetworkDestination())); jGen.writeNumberField("networkDestinationMaskLen", match.getNetworkDestinationMaskLen()); jGen.writeNumberField("networkProtocol", match.getNetworkProtocol()); jGen.writeStringField("networkSource", intToIp(match.getNetworkSource())); jGen.writeNumberField("networkSourceMaskLen", match.getNetworkSourceMaskLen()); jGen.writeNumberField("networkTypeOfService", match.getNetworkTypeOfService()); jGen.writeNumberField("transportDestination", match.getTransportDestination()); jGen.writeNumberField("transportSource", match.getTransportSource()); jGen.writeNumberField("wildcards", match.getWildcards()); jGen.writeEndObject(); } /** * Tells SimpleModule that we are the serializer for OFMatch */ @Override public Class handledType() { return OFMatch.class; } } floodlight-0.90/src/main/java/org/openflow/protocol/serializers/OFFeaturesReplyJSONSerializer.java0000664000175000017500000000440612041336206034131 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.serializers; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.openflow.protocol.OFFeaturesReply; import org.openflow.util.HexString; public class OFFeaturesReplyJSONSerializer extends JsonSerializer { /** * Performs the serialization of a OFFeaturesReply object */ @Override public void serialize(OFFeaturesReply reply, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { jGen.writeStartObject(); jGen.writeNumberField("actions", reply.getActions()); jGen.writeNumberField("buffers", reply.getBuffers()); jGen.writeNumberField("capabilities", reply.getCapabilities()); jGen.writeStringField("datapathId", HexString.toHexString(reply.getDatapathId())); jGen.writeNumberField("length", reply.getLength()); serializer.defaultSerializeField("ports", reply.getPorts(), jGen); jGen.writeNumberField("tables", reply.getTables()); jGen.writeStringField("type", reply.getType().toString()); jGen.writeNumberField("version", reply.getVersion()); jGen.writeNumberField("xid", reply.getXid()); jGen.writeEndObject(); } /** * Tells SimpleModule that we are the serializer for OFFeaturesReply */ @Override public Class handledType() { return OFFeaturesReply.class; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFVendor.java0000664000175000017500000000713612041336206025517 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; import org.openflow.protocol.factory.OFVendorDataFactory; import org.openflow.protocol.factory.OFVendorDataFactoryAware; import org.openflow.protocol.vendor.OFVendorData; /** * Represents ofp_vendor_header * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFVendor extends OFMessage implements OFVendorDataFactoryAware { public static int MINIMUM_LENGTH = 12; protected int vendor; protected OFVendorData vendorData; protected OFVendorDataFactory vendorDataFactory; public OFVendor() { super(); this.type = OFType.VENDOR; this.length = U16.t(MINIMUM_LENGTH); } /** * @return the vendor */ public int getVendor() { return vendor; } /** * @param vendor the vendor to set */ public void setVendor(int vendor) { this.vendor = vendor; } /** * @return the data */ public OFVendorData getVendorData() { return vendorData; } /** * @param data the data to set */ public void setVendorData(OFVendorData vendorData) { this.vendorData = vendorData; } @Override public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory) { this.vendorDataFactory = vendorDataFactory; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.vendor = data.readInt(); if (vendorDataFactory == null) throw new RuntimeException("OFVendorDataFactory not set"); this.vendorData = vendorDataFactory.parseVendorData(vendor, data, super.getLengthU() - MINIMUM_LENGTH); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(this.vendor); if (vendorData != null) vendorData.writeTo(data); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 337; int result = super.hashCode(); result = prime * result + vendor; if (vendorData != null) result = prime * result + vendorData.hashCode(); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OFVendor other = (OFVendor) obj; if (vendor != other.vendor) return false; if (vendorData == null) { if (other.vendorData != null) { return false; } } else if (!vendorData.equals(other.vendorData)) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFSetConfig.java0000664000175000017500000000170112041336206026133 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; /** * Represents an OFPT_SET_CONFIG type message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFSetConfig extends OFSwitchConfig { public OFSetConfig() { super(); this.type = OFType.SET_CONFIG; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFEchoReply.java0000664000175000017500000000206012041336206026143 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an ofp_echo_reply message * * @author Rob Sherwood (rob.sherwood@stanford.edu) */ public class OFEchoReply extends OFEchoRequest { public static int MINIMUM_LENGTH = 8; public OFEchoReply() { super(); this.type = OFType.ECHO_REPLY; this.length = U16.t(MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/factory/0000775000175000017500000000000012041336206024632 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/factory/MessageParseException.java0000664000175000017500000000127412041336206031737 0ustar jamespagejamespagepackage org.openflow.protocol.factory; /** * Exception thrown when an openflow message fails to parse properly */ public class MessageParseException extends Exception { /** * */ private static final long serialVersionUID = -75893812926304726L; public MessageParseException() { super(); } public MessageParseException(String message, Throwable cause) { super(message, cause); this.setStackTrace(cause.getStackTrace()); } public MessageParseException(String message) { super(message); } public MessageParseException(Throwable cause) { super(cause); this.setStackTrace(cause.getStackTrace()); } } floodlight-0.90/src/main/java/org/openflow/protocol/factory/OFActionFactory.java0000664000175000017500000000442412041336206030473 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionType; /** * The interface to factories used for retrieving OFAction instances. All * methods are expected to be thread-safe. * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface OFActionFactory { /** * Retrieves an OFAction instance corresponding to the specified * OFActionType * @param t the type of the OFAction to be retrieved * @return an OFAction instance */ public OFAction getAction(OFActionType t); /** * Attempts to parse and return all OFActions contained in the given * ByteBuffer, beginning at the ByteBuffer's position, and ending at * position+length. * @param data the ChannelBuffer to parse for OpenFlow actions * @param length the number of Bytes to examine for OpenFlow actions * @return a list of OFAction instances */ public List parseActions(ChannelBuffer data, int length); /** * Attempts to parse and return all OFActions contained in the given * ByteBuffer, beginning at the ByteBuffer's position, and ending at * position+length. * @param data the ChannelBuffer to parse for OpenFlow actions * @param length the number of Bytes to examine for OpenFlow actions * @param limit the maximum number of messages to return, 0 means no limit * @return a list of OFAction instances */ public List parseActions(ChannelBuffer data, int length, int limit); } floodlight-0.90/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java0000664000175000017500000000206612041336206031453 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; /** * Objects implementing this interface are expected to be instantiated with an * instance of an OFActionFactory * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface OFActionFactoryAware { /** * Sets the OFActionFactory * @param actionFactory */ public void setActionFactory(OFActionFactory actionFactory); } floodlight-0.90/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java0000664000175000017500000000570312041336206031411 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFType; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; /** * The interface to factories used for retrieving OFStatistics instances. All * methods are expected to be thread-safe. * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface OFStatisticsFactory { /** * Retrieves an OFStatistics instance corresponding to the specified * OFStatisticsType * @param t the type of the containing OFMessage, only accepts statistics * request or reply * @param st the type of the OFStatistics to be retrieved * @return an OFStatistics instance */ public OFStatistics getStatistics(OFType t, OFStatisticsType st); /** * Attempts to parse and return all OFStatistics contained in the given * ByteBuffer, beginning at the ByteBuffer's position, and ending at * position+length. * @param t the type of the containing OFMessage, only accepts statistics * request or reply * @param st the type of the OFStatistics to be retrieved * @param data the ChannelBuffer to parse for OpenFlow Statistics * @param length the number of Bytes to examine for OpenFlow Statistics * @return a list of OFStatistics instances */ public List parseStatistics(OFType t, OFStatisticsType st, ChannelBuffer data, int length); /** * Attempts to parse and return all OFStatistics contained in the given * ByteBuffer, beginning at the ByteBuffer's position, and ending at * position+length. * @param t the type of the containing OFMessage, only accepts statistics * request or reply * @param st the type of the OFStatistics to be retrieved * @param data the ChannelBuffer to parse for OpenFlow Statistics * @param length the number of Bytes to examine for OpenFlow Statistics * @param limit the maximum number of messages to return, 0 means no limit * @return a list of OFStatistics instances */ public List parseStatistics(OFType t, OFStatisticsType st, ChannelBuffer data, int length, int limit); } floodlight-0.90/src/main/java/org/openflow/protocol/factory/BasicFactory.java0000664000175000017500000002406012041336206030050 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; import java.util.ArrayList; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionType; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.protocol.statistics.OFVendorStatistics; import org.openflow.protocol.vendor.OFByteArrayVendorData; import org.openflow.protocol.vendor.OFVendorData; import org.openflow.protocol.vendor.OFVendorDataType; import org.openflow.protocol.vendor.OFVendorId; /** * A basic OpenFlow factory that supports naive creation of both Messages and * Actions. * * @author David Erickson (daviderickson@cs.stanford.edu) * @author Rob Sherwood (rob.sherwood@stanford.edu) * */ public class BasicFactory implements OFMessageFactory, OFActionFactory, OFStatisticsFactory, OFVendorDataFactory { @Override public OFMessage getMessage(OFType t) { return t.newInstance(); } @Override public List parseMessage(ChannelBuffer data) throws MessageParseException { List msglist = new ArrayList(); OFMessage msg = null; while (data.readableBytes() >= OFMessage.MINIMUM_LENGTH) { data.markReaderIndex(); msg = this.parseMessageOne(data); if (msg == null) { data.resetReaderIndex(); break; } else { msglist.add(msg); } } if (msglist.size() == 0) { return null; } return msglist; } public OFMessage parseMessageOne(ChannelBuffer data) throws MessageParseException { try { OFMessage demux = new OFMessage(); OFMessage ofm = null; if (data.readableBytes() < OFMessage.MINIMUM_LENGTH) return ofm; data.markReaderIndex(); demux.readFrom(data); data.resetReaderIndex(); if (demux.getLengthU() > data.readableBytes()) return ofm; ofm = getMessage(demux.getType()); if (ofm == null) return null; if (ofm instanceof OFActionFactoryAware) { ((OFActionFactoryAware)ofm).setActionFactory(this); } if (ofm instanceof OFMessageFactoryAware) { ((OFMessageFactoryAware)ofm).setMessageFactory(this); } if (ofm instanceof OFStatisticsFactoryAware) { ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this); } if (ofm instanceof OFVendorDataFactoryAware) { ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this); } ofm.readFrom(data); if (OFMessage.class.equals(ofm.getClass())) { // advance the position for un-implemented messages data.readerIndex(data.readerIndex()+(ofm.getLengthU() - OFMessage.MINIMUM_LENGTH)); } return ofm; } catch (Exception e) { /* Write the offending data along with the error message */ data.resetReaderIndex(); String msg = "Message Parse Error for packet:" + dumpBuffer(data) + "\nException: " + e.toString(); data.resetReaderIndex(); throw new MessageParseException(msg, e); } } @Override public OFAction getAction(OFActionType t) { return t.newInstance(); } @Override public List parseActions(ChannelBuffer data, int length) { return parseActions(data, length, 0); } @Override public List parseActions(ChannelBuffer data, int length, int limit) { List results = new ArrayList(); OFAction demux = new OFAction(); OFAction ofa; int end = data.readerIndex() + length; while (limit == 0 || results.size() <= limit) { if ((data.readableBytes() < OFAction.MINIMUM_LENGTH || (data.readerIndex() + OFAction.MINIMUM_LENGTH) > end)) return results; data.markReaderIndex(); demux.readFrom(data); data.resetReaderIndex(); if ((demux.getLengthU() > data.readableBytes() || (data.readerIndex() + demux.getLengthU()) > end)) return results; ofa = getAction(demux.getType()); ofa.readFrom(data); if (OFAction.class.equals(ofa.getClass())) { // advance the position for un-implemented messages data.readerIndex(data.readerIndex()+(ofa.getLengthU() - OFAction.MINIMUM_LENGTH)); } results.add(ofa); } return results; } @Override public OFActionFactory getActionFactory() { return this; } @Override public OFStatistics getStatistics(OFType t, OFStatisticsType st) { return st.newInstance(t); } @Override public List parseStatistics(OFType t, OFStatisticsType st, ChannelBuffer data, int length) { return parseStatistics(t, st, data, length, 0); } /** * @param t * OFMessage type: should be one of stats_request or stats_reply * @param st * statistics type of this message, e.g., DESC, TABLE * @param data * buffer to read from * @param length * length of statistics * @param limit * number of statistics to grab; 0 == all * * @return list of statistics */ @Override public List parseStatistics(OFType t, OFStatisticsType st, ChannelBuffer data, int length, int limit) { List results = new ArrayList(); OFStatistics statistics = getStatistics(t, st); int start = data.readerIndex(); int count = 0; while (limit == 0 || results.size() <= limit) { // TODO Create a separate MUX/DEMUX path for vendor stats if (statistics instanceof OFVendorStatistics) ((OFVendorStatistics)statistics).setLength(length); /** * can't use data.remaining() here, b/c there could be other data * buffered past this message */ if ((length - count) >= statistics.getLength()) { if (statistics instanceof OFActionFactoryAware) ((OFActionFactoryAware)statistics).setActionFactory(this); statistics.readFrom(data); results.add(statistics); count += statistics.getLength(); statistics = getStatistics(t, st); } else { if (count < length) { /** * Nasty case: partial/incomplete statistic found even * though we have a full message. Found when NOX sent * agg_stats request with wrong agg statistics length (52 * instead of 56) * * just throw the rest away, or we will break framing */ data.readerIndex(start + length); } return results; } } return results; // empty; no statistics at all } @Override public OFVendorData getVendorData(OFVendorId vendorId, OFVendorDataType vendorDataType) { if (vendorDataType == null) return null; return vendorDataType.newInstance(); } /** * Attempts to parse and return the OFVendorData contained in the given * ChannelBuffer, beginning right after the vendor id. * @param vendor the vendor id that was parsed from the OFVendor message. * @param data the ChannelBuffer from which to parse the vendor data * @param length the length to the end of the enclosing message. * @return an OFVendorData instance */ public OFVendorData parseVendorData(int vendor, ChannelBuffer data, int length) { OFVendorDataType vendorDataType = null; OFVendorId vendorId = OFVendorId.lookupVendorId(vendor); if (vendorId != null) { data.markReaderIndex(); vendorDataType = vendorId.parseVendorDataType(data, length); data.resetReaderIndex(); } OFVendorData vendorData = getVendorData(vendorId, vendorDataType); if (vendorData == null) vendorData = new OFByteArrayVendorData(); vendorData.readFrom(data, length); return vendorData; } public static String dumpBuffer(ChannelBuffer data) { // NOTE: Reads all the bytes in buffer from current read offset. // Set/Reset ReaderIndex if you want to read from a different location int len = data.readableBytes(); StringBuffer sb = new StringBuffer(); for (int i=0 ; i parseMessage(ChannelBuffer data) throws MessageParseException; /** * Retrieves an OFActionFactory * @return an OFActionFactory */ public OFActionFactory getActionFactory(); } floodlight-0.90/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java0000664000175000017500000000204112041336206032256 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; /** * Classes implementing this interface are expected to be instantiated with an * instance of an OFVendorDataFactory * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public interface OFVendorDataFactoryAware { public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory); } floodlight-0.90/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java0000664000175000017500000000212212041336206032361 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.factory; /** * Objects implementing this interface are expected to be instantiated with an * instance of an OFStatisticsFactory * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface OFStatisticsFactoryAware { /** * Sets the OFStatisticsFactory * @param statisticsFactory */ public void setStatisticsFactory(OFStatisticsFactory statisticsFactory); } floodlight-0.90/src/main/java/org/openflow/protocol/action/0000775000175000017500000000000012041336206024440 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java0000664000175000017500000000536212041336206032760 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_vlan_vid * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFActionVirtualLanIdentifier extends OFAction { public static int MINIMUM_LENGTH = 8; protected short virtualLanIdentifier; public OFActionVirtualLanIdentifier() { super.setType(OFActionType.SET_VLAN_ID); super.setLength((short) MINIMUM_LENGTH); } public OFActionVirtualLanIdentifier(short vlanId) { this(); this.virtualLanIdentifier = vlanId; } /** * @return the virtualLanIdentifier */ public short getVirtualLanIdentifier() { return virtualLanIdentifier; } /** * @param virtualLanIdentifier the virtualLanIdentifier to set */ public void setVirtualLanIdentifier(short virtualLanIdentifier) { this.virtualLanIdentifier = virtualLanIdentifier; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.virtualLanIdentifier = data.readShort(); data.readShort(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.virtualLanIdentifier); data.writeShort((short) 0); } @Override public int hashCode() { final int prime = 383; int result = super.hashCode(); result = prime * result + virtualLanIdentifier; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionVirtualLanIdentifier)) { return false; } OFActionVirtualLanIdentifier other = (OFActionVirtualLanIdentifier) obj; if (virtualLanIdentifier != other.virtualLanIdentifier) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionOutput.java0000664000175000017500000001013212041336206030163 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 * @author Rob Sherwood (rob.sherwood@stanford.edu) */ public class OFActionOutput extends OFAction implements Cloneable { public static int MINIMUM_LENGTH = 8; protected short port; protected short maxLength; public OFActionOutput() { super.setType(OFActionType.OUTPUT); super.setLength((short) MINIMUM_LENGTH); } /** * Create an Output Action sending packets out the specified * OpenFlow port. * * This is the most common creation pattern for OFActions. * * @param port */ public OFActionOutput(short port) { this(port, (short) 65535); } /** * Create an Output Action specifying both the port AND * the snaplen of the packet to send out that port. * The length field is only meaningful when port == OFPort.OFPP_CONTROLLER * @param port * @param maxLength The maximum number of bytes of the packet to send. * Most hardware only supports this value for OFPP_CONTROLLER */ public OFActionOutput(short port, short maxLength) { super(); super.setType(OFActionType.OUTPUT); super.setLength((short) MINIMUM_LENGTH); this.port = port; this.maxLength = maxLength; } /** * Get the output port * @return */ public short getPort() { return this.port; } /** * Set the output port * @param port */ public OFActionOutput setPort(short port) { this.port = port; return this; } /** * Get the max length to send to the controller * @return */ public short getMaxLength() { return this.maxLength; } /** * Set the max length to send to the controller * @param maxLength */ public OFActionOutput setMaxLength(short maxLength) { this.maxLength = maxLength; return this; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.port = data.readShort(); this.maxLength = data.readShort(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(port); data.writeShort(maxLength); } @Override public int hashCode() { final int prime = 367; int result = super.hashCode(); result = prime * result + maxLength; result = prime * result + port; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionOutput)) { return false; } OFActionOutput other = (OFActionOutput) obj; if (maxLength != other.maxLength) { return false; } if (port != other.port) { return false; } return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "OFActionOutput [maxLength=" + maxLength + ", port=" + U16.f(port) + ", length=" + length + ", type=" + type + "]"; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java0000664000175000017500000000450012041336206032621 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_nw_addr * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public abstract class OFActionNetworkLayerAddress extends OFAction { public static int MINIMUM_LENGTH = 8; protected int networkAddress; /** * @return the networkAddress */ public int getNetworkAddress() { return networkAddress; } /** * @param networkAddress the networkAddress to set */ public void setNetworkAddress(int networkAddress) { this.networkAddress = networkAddress; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.networkAddress = data.readInt(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(this.networkAddress); } @Override public int hashCode() { final int prime = 353; int result = super.hashCode(); result = prime * result + networkAddress; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionNetworkLayerAddress)) { return false; } OFActionNetworkLayerAddress other = (OFActionNetworkLayerAddress) obj; if (networkAddress != other.networkAddress) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java0000664000175000017500000000551112041336206030536 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import java.util.Arrays; import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.OFPhysicalPort; /** * Represents an ofp_action_dl_addr * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public abstract class OFActionDataLayer extends OFAction { public static int MINIMUM_LENGTH = 16; protected byte[] dataLayerAddress; /** * @return the dataLayerAddress */ @JsonSerialize(using=ByteArrayMACSerializer.class) public byte[] getDataLayerAddress() { return dataLayerAddress; } /** * @param dataLayerAddress the dataLayerAddress to set */ public void setDataLayerAddress(byte[] dataLayerAddress) { this.dataLayerAddress = dataLayerAddress; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); if (this.dataLayerAddress == null) this.dataLayerAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN]; data.readBytes(this.dataLayerAddress); data.readInt(); data.readShort(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeBytes(this.dataLayerAddress); data.writeInt(0); data.writeShort((short) 0); } @Override public int hashCode() { final int prime = 347; int result = super.hashCode(); result = prime * result + Arrays.hashCode(dataLayerAddress); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionDataLayer)) { return false; } OFActionDataLayer other = (OFActionDataLayer) obj; if (!Arrays.equals(dataLayerAddress, other.dataLayerAddress)) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java0000664000175000017500000000454512041336206031667 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_tp_port * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public abstract class OFActionTransportLayer extends OFAction { public static int MINIMUM_LENGTH = 8; protected short transportPort; /** * @return the transportPort */ public short getTransportPort() { return transportPort; } /** * @param transportPort the transportPort to set */ public void setTransportPort(short transportPort) { this.transportPort = transportPort; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.transportPort = data.readShort(); data.readShort(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.transportPort); data.writeShort((short) 0); } @Override public int hashCode() { final int prime = 373; int result = super.hashCode(); result = prime * result + transportPort; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionTransportLayer)) { return false; } OFActionTransportLayer other = (OFActionTransportLayer) obj; if (transportPort != other.transportPort) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java0000664000175000017500000000217512041336206031722 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionDataLayerSource extends OFActionDataLayer { public OFActionDataLayerSource() { super(); super.setType(OFActionType.SET_DL_SRC); super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH); } public OFActionDataLayerSource(byte[] address) { this(); this.dataLayerAddress = address; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionVendor.java0000664000175000017500000000423612041336206030130 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionVendor extends OFAction { public static int MINIMUM_LENGTH = 8; protected int vendor; public OFActionVendor() { super(); super.setType(OFActionType.VENDOR); super.setLength((short) MINIMUM_LENGTH); } /** * @return the vendor */ public int getVendor() { return vendor; } /** * @param vendor the vendor to set */ public void setVendor(int vendor) { this.vendor = vendor; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.vendor = data.readInt(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(this.vendor); } @Override public int hashCode() { final int prime = 379; int result = super.hashCode(); result = prime * result + vendor; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionVendor)) { return false; } OFActionVendor other = (OFActionVendor) obj; if (vendor != other.vendor) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java0000664000175000017500000000576412041336206030311 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_enqueue * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFActionEnqueue extends OFAction { public static int MINIMUM_LENGTH = 16; protected short port; protected int queueId; public OFActionEnqueue() { super.setType(OFActionType.OPAQUE_ENQUEUE); super.setLength((short) MINIMUM_LENGTH); } public OFActionEnqueue(short port, int queueId) { this(); this.port = port; this.queueId = queueId; } /** * Get the output port * @return */ public short getPort() { return this.port; } /** * Set the output port * @param port */ public void setPort(short port) { this.port = port; } /** * @return the queueId */ public int getQueueId() { return queueId; } /** * @param queueId the queueId to set */ public void setQueueId(int queueId) { this.queueId = queueId; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.port = data.readShort(); data.readShort(); data.readInt(); this.queueId = data.readInt(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.port); data.writeShort((short) 0); data.writeInt(0); data.writeInt(this.queueId); } @Override public int hashCode() { final int prime = 349; int result = super.hashCode(); result = prime * result + port; result = prime * result + queueId; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionEnqueue)) { return false; } OFActionEnqueue other = (OFActionEnqueue) obj; if (port != other.port) { return false; } if (queueId != other.queueId) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java0000664000175000017500000000544412041336206032776 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_enqueue * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFActionNetworkTypeOfService extends OFAction { public static int MINIMUM_LENGTH = 8; protected byte networkTypeOfService; public OFActionNetworkTypeOfService() { super.setType(OFActionType.SET_NW_TOS); super.setLength((short) MINIMUM_LENGTH); } public OFActionNetworkTypeOfService(byte tos) { this(); this.networkTypeOfService = tos; } /** * @return the networkTypeOfService */ public byte getNetworkTypeOfService() { return networkTypeOfService; } /** * @param networkTypeOfService the networkTypeOfService to set */ public void setNetworkTypeOfService(byte networkTypeOfService) { this.networkTypeOfService = networkTypeOfService; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.networkTypeOfService = data.readByte(); data.readShort(); data.readByte(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeByte(this.networkTypeOfService); data.writeShort((short) 0); data.writeByte((byte) 0); } @Override public int hashCode() { final int prime = 359; int result = super.hashCode(); result = prime * result + networkTypeOfService; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionNetworkTypeOfService)) { return false; } OFActionNetworkTypeOfService other = (OFActionNetworkTypeOfService) obj; if (networkTypeOfService != other.networkTypeOfService) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java0000664000175000017500000000273112041336206031774 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_strip_vlan * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFActionStripVirtualLan extends OFAction { public static int MINIMUM_LENGTH = 8; public OFActionStripVirtualLan() { super(); super.setType(OFActionType.STRIP_VLAN); super.setLength((short) MINIMUM_LENGTH); } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); // PAD data.readInt(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); // PAD data.writeInt(0); } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java0000664000175000017500000000221312041336206032473 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionNetworkLayerSource extends OFActionNetworkLayerAddress { public OFActionNetworkLayerSource() { super(); super.setType(OFActionType.SET_NW_SRC); super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH); } public OFActionNetworkLayerSource(int ip) { this(); this.networkAddress = ip; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFAction.java0000664000175000017500000001114212041336206026744 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * The base class for all OpenFlow Actions. * * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFAction implements Cloneable { /** * Note the true minimum length for this header is 8 including a pad to 64 * bit alignment, however as this base class is used for demuxing an * incoming Action, it is only necessary to read the first 4 bytes. All * Actions extending this class are responsible for reading/writing the * first 8 bytes, including the pad if necessary. */ public static int MINIMUM_LENGTH = 4; public static int OFFSET_LENGTH = 2; public static int OFFSET_TYPE = 0; protected OFActionType type; protected short length; /** * Get the length of this message * * @return */ public short getLength() { return length; } /** * Get the length of this message, unsigned * * @return */ public int getLengthU() { return U16.f(length); } /** * Set the length of this message * * @param length */ public OFAction setLength(short length) { this.length = length; return this; } /** * Get the type of this message * * @return OFActionType enum */ public OFActionType getType() { return this.type; } /** * Set the type of this message * * @param type */ public void setType(OFActionType type) { this.type = type; } /** * Returns a summary of the message * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid" */ public String toString() { return "ofaction" + ";t=" + this.getType() + ";l=" + this.getLength(); } /** * Given the output from toString(), * create a new OFAction * @param val * @return */ public static OFAction fromString(String val) { String tokens[] = val.split(";"); if (!tokens[0].equals("ofaction")) throw new IllegalArgumentException("expected 'ofaction' but got '" + tokens[0] + "'"); String type_tokens[] = tokens[1].split("="); String len_tokens[] = tokens[2].split("="); OFAction action = new OFAction(); action.setLength(Short.valueOf(len_tokens[1])); action.setType(OFActionType.valueOf(type_tokens[1])); return action; } public void readFrom(ChannelBuffer data) { this.type = OFActionType.valueOf(data.readShort()); this.length = data.readShort(); // Note missing PAD, see MINIMUM_LENGTH comment for details } public void writeTo(ChannelBuffer data) { data.writeShort(type.getTypeValue()); data.writeShort(length); // Note missing PAD, see MINIMUM_LENGTH comment for details } @Override public int hashCode() { final int prime = 347; int result = 1; result = prime * result + length; result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFAction)) { return false; } OFAction other = (OFAction) obj; if (length != other.length) { return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } return true; } /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override public OFAction clone() throws CloneNotSupportedException { return (OFAction) super.clone(); } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java0000664000175000017500000000572412041336206034326 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ package org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; /** * Represents an ofp_action_vlan_pcp * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFActionVirtualLanPriorityCodePoint extends OFAction { public static int MINIMUM_LENGTH = 8; protected byte virtualLanPriorityCodePoint; public OFActionVirtualLanPriorityCodePoint() { super.setType(OFActionType.SET_VLAN_PCP); super.setLength((short) MINIMUM_LENGTH); } public OFActionVirtualLanPriorityCodePoint(byte priority) { this(); this.virtualLanPriorityCodePoint = priority; } /** * @return the virtualLanPriorityCodePoint */ public byte getVirtualLanPriorityCodePoint() { return virtualLanPriorityCodePoint; } /** * @param virtualLanPriorityCodePoint the virtualLanPriorityCodePoint to set */ public void setVirtualLanPriorityCodePoint(byte virtualLanPriorityCodePoint) { this.virtualLanPriorityCodePoint = virtualLanPriorityCodePoint; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.virtualLanPriorityCodePoint = data.readByte(); data.readShort(); // pad data.readByte(); // pad } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeByte(this.virtualLanPriorityCodePoint); data.writeShort((short) 0); data.writeByte((byte) 0); } @Override public int hashCode() { final int prime = 389; int result = super.hashCode(); result = prime * result + virtualLanPriorityCodePoint; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFActionVirtualLanPriorityCodePoint)) { return false; } OFActionVirtualLanPriorityCodePoint other = (OFActionVirtualLanPriorityCodePoint) obj; if (virtualLanPriorityCodePoint != other.virtualLanPriorityCodePoint) { return false; } return true; } }floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java0000664000175000017500000000223312041336206034061 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionTransportLayerDestination extends OFActionTransportLayer { public OFActionTransportLayerDestination() { super(); super.setType(OFActionType.SET_TP_DST); super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH); } public OFActionTransportLayerDestination(short port) { this(); this.transportPort = port; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java0000664000175000017500000000221412041336206032735 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionDataLayerDestination extends OFActionDataLayer { public OFActionDataLayerDestination() { super(); super.setType(OFActionType.SET_DL_DST); super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH); } public OFActionDataLayerDestination(byte[] address) { this(); this.dataLayerAddress = address; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java0000664000175000017500000000221412041336206033037 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionTransportLayerSource extends OFActionTransportLayer { public OFActionTransportLayerSource() { super(); super.setType(OFActionType.SET_TP_SRC); super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH); } public OFActionTransportLayerSource(short port) { this(); this.transportPort = port; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionType.java0000664000175000017500000001734312041336206027617 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package org.openflow.protocol.action; import java.lang.reflect.Constructor; import org.openflow.protocol.Instantiable; /** * List of OpenFlow Action types and mappings to wire protocol value and * derived classes * * @author David Erickson (daviderickson@cs.stanford.edu) */ public enum OFActionType { OUTPUT (0, OFActionOutput.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionOutput(); }}), SET_VLAN_ID (1, OFActionVirtualLanIdentifier.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionVirtualLanIdentifier(); }}), SET_VLAN_PCP (2, OFActionVirtualLanPriorityCodePoint.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionVirtualLanPriorityCodePoint(); }}), STRIP_VLAN (3, OFActionStripVirtualLan.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionStripVirtualLan(); }}), SET_DL_SRC (4, OFActionDataLayerSource.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionDataLayerSource(); }}), SET_DL_DST (5, OFActionDataLayerDestination.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionDataLayerDestination(); }}), SET_NW_SRC (6, OFActionNetworkLayerSource.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionNetworkLayerSource(); }}), SET_NW_DST (7, OFActionNetworkLayerDestination.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionNetworkLayerDestination(); }}), SET_NW_TOS (8, OFActionNetworkTypeOfService.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionNetworkTypeOfService(); }}), SET_TP_SRC (9, OFActionTransportLayerSource.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionTransportLayerSource(); }}), SET_TP_DST (10, OFActionTransportLayerDestination.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionTransportLayerDestination(); }}), OPAQUE_ENQUEUE (11, OFActionEnqueue.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionEnqueue(); }}), VENDOR (0xffff, OFActionVendor.class, new Instantiable() { @Override public OFAction instantiate() { return new OFActionVendor(); }}); protected static OFActionType[] mapping; protected Class clazz; protected Constructor constructor; protected Instantiable instantiable; protected int minLen; protected short type; /** * Store some information about the OpenFlow Action type, including wire * protocol type number, length, and derrived class * * @param type Wire protocol number associated with this OFType * @param clazz The Java class corresponding to this type of OpenFlow Action * @param instantiable the instantiable for the OFAction this type represents */ OFActionType(int type, Class clazz, Instantiable instantiable) { this.type = (short) type; this.clazz = clazz; this.instantiable = instantiable; try { this.constructor = clazz.getConstructor(new Class[]{}); } catch (Exception e) { throw new RuntimeException( "Failure getting constructor for class: " + clazz, e); } OFActionType.addMapping(this.type, this); } /** * Adds a mapping from type value to OFActionType enum * * @param i OpenFlow wire protocol Action type value * @param t type */ static public void addMapping(short i, OFActionType t) { if (mapping == null) mapping = new OFActionType[16]; // bring higher mappings down to the edge of our array if (i < 0) i = (short) (16 + i); OFActionType.mapping[i] = t; } /** * Given a wire protocol OpenFlow type number, return the OFType associated * with it * * @param i wire protocol number * @return OFType enum type */ static public OFActionType valueOf(short i) { if (i < 0) i = (short) (16+i); return OFActionType.mapping[i]; } /** * @return Returns the wire protocol value corresponding to this * OFActionType */ public short getTypeValue() { return this.type; } /** * @return return the OFAction subclass corresponding to this OFActionType */ public Class toClass() { return clazz; } /** * Returns the no-argument Constructor of the implementation class for * this OFActionType * @return the constructor */ public Constructor getConstructor() { return constructor; } /** * Returns a new instance of the OFAction represented by this OFActionType * @return the new object */ public OFAction newInstance() { return instantiable.instantiate(); } /** * @return the instantiable */ public Instantiable getInstantiable() { return instantiable; } /** * @param instantiable the instantiable to set */ public void setInstantiable(Instantiable instantiable) { this.instantiable = instantiable; } } floodlight-0.90/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java0000664000175000017500000000223212041336206033515 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.action; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFActionNetworkLayerDestination extends OFActionNetworkLayerAddress { public OFActionNetworkLayerDestination() { super(); super.setType(OFActionType.SET_NW_DST); super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH); } public OFActionNetworkLayerDestination(int ip) { this(); this.networkAddress = ip; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFFeaturesRequest.java0000664000175000017500000000210412041336206027377 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents a features request message * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class OFFeaturesRequest extends OFMessage { public static int MINIMUM_LENGTH = 8; public OFFeaturesRequest() { super(); this.type = OFType.FEATURES_REQUEST; this.length = U16.t(MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFSwitchConfig.java0000664000175000017500000000565512041336206026655 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.jboss.netty.buffer.ChannelBuffer; /** * Base class representing ofp_switch_config based messages * @author David Erickson (daviderickson@cs.stanford.edu) */ public abstract class OFSwitchConfig extends OFMessage { public static int MINIMUM_LENGTH = 12; public enum OFConfigFlags { OFPC_FRAG_NORMAL, OFPC_FRAG_DROP, OFPC_FRAG_REASM, OFPC_FRAG_MASK } protected short flags; protected short missSendLength; public OFSwitchConfig() { super(); super.setLengthU(MINIMUM_LENGTH); } /** * @return the flags */ public short getFlags() { return flags; } /** * @param flags the flags to set */ public OFSwitchConfig setFlags(short flags) { this.flags = flags; return this; } /** * @return the missSendLength */ public short getMissSendLength() { return missSendLength; } /** * @param missSendLength the missSendLength to set */ public OFSwitchConfig setMissSendLength(short missSendLength) { this.missSendLength = missSendLength; return this; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.flags = data.readShort(); this.missSendLength = data.readShort(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(this.flags); data.writeShort(this.missSendLength); } @Override public int hashCode() { final int prime = 331; int result = super.hashCode(); result = prime * result + flags; result = prime * result + missSendLength; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFSwitchConfig)) { return false; } OFSwitchConfig other = (OFSwitchConfig) obj; if (flags != other.flags) { return false; } if (missSendLength != other.missSendLength) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/0000775000175000017500000000000012041336206024460 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java0000664000175000017500000000457712041336206030456 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import org.openflow.protocol.Instantiable; /** * Class that represents a specific vendor data type format in an * OFVendor message. Typically the vendor data will begin with an integer * code that determines the format of the rest of the data, but this * class does not assume that. It's basically just a holder for an * instantiator of the appropriate subclass of OFVendorData. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFVendorDataType { /** * Object that instantiates the subclass of OFVendorData * associated with this data type. */ protected Instantiable instantiable; /** * Construct an empty vendor data type. */ public OFVendorDataType() { super(); } /** * Construct a vendor data type with the specified instantiable. * @param instantiable object that creates the subclass of OFVendorData * associated with this data type. */ public OFVendorDataType(Instantiable instantiable) { this.instantiable = instantiable; } /** * Returns a new instance of a subclass of OFVendorData associated with * this OFVendorDataType. * * @return the new object */ public OFVendorData newInstance() { return instantiable.instantiate(); } /** * @return the instantiable */ public Instantiable getInstantiable() { return instantiable; } /** * @param instantiable the instantiable to set */ public void setInstantiable(Instantiable instantiable) { this.instantiable = instantiable; } } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFVendorData.java0000664000175000017500000000244012041336206027577 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import org.jboss.netty.buffer.ChannelBuffer; /** * The base class for all vendor data. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public interface OFVendorData { /** * @return length of the data */ public int getLength(); /** * Read the vendor data from the specified ChannelBuffer * @param data */ public void readFrom(ChannelBuffer data, int length); /** * Write the vendor data to the specified ChannelBuffer * @param data */ public void writeTo(ChannelBuffer data); } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java0000664000175000017500000000452612041336206031412 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import org.openflow.protocol.Instantiable; /** * Subclass of OFVendorDataType that works with any vendor data format that * begins with a integral value to indicate the format of the remaining data. * It maps from the per-vendor-id integral data type code to the object * used to instantiate the class associated with that vendor data type. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFBasicVendorDataType extends OFVendorDataType { /** * The data type value at the beginning of the vendor data. */ protected long type; /** * Construct an empty (i.e. no specified data type value) vendor data type. */ public OFBasicVendorDataType() { super(); this.type = 0; } /** * Store some information about the vendor data type, including wire protocol * type number, derived class and instantiator. * * @param type Wire protocol number associated with this vendor data type * @param instantiator An Instantiator implementation that * creates an instance of an appropriate subclass of OFVendorData. */ public OFBasicVendorDataType(long type, Instantiable instantiator) { super(instantiator); this.type = type; } /** * @return Returns the wire protocol value corresponding to this OFVendorDataType */ public long getTypeValue() { return this.type; } /** * @param type the wire protocol value for this data type */ public void setTypeValue(long type) { this.type = type; } } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java0000664000175000017500000000541612041336206031430 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import org.jboss.netty.buffer.ChannelBuffer; /** * Basic implementation of OFVendorData that just treats the data as a * byte array. This is used if there's an OFVendor message where there's * no registered OFVendorId or no specific OFVendorDataType that can be * determined from the data. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFByteArrayVendorData implements OFVendorData { protected byte[] bytes; /** * Construct vendor data with an empty byte array. */ public OFByteArrayVendorData() { } /** * Construct vendor data with the specified byte array. * @param bytes */ public OFByteArrayVendorData(byte[] bytes) { this.bytes = bytes; } /** * Get the associated byte array for this vendor data. * @return the byte array containing the raw vendor data. */ public byte[] getBytes() { return bytes; } /** * Set the byte array for the vendor data. * @param bytes the raw byte array containing the vendor data. */ public void setBytes(byte[] bytes) { this.bytes = bytes; } /** * Get the length of the vendor data. In this case it's just then length * of the underlying byte array. * @return the length of the vendor data */ @Override public int getLength() { return (bytes != null) ? bytes.length : 0; } /** * Read the vendor data from the ChannelBuffer into the byte array. * @param data the channel buffer from which we're deserializing * @param length the length to the end of the enclosing message */ @Override public void readFrom(ChannelBuffer data, int length) { bytes = new byte[length]; data.readBytes(bytes); } /** * Write the vendor data bytes to the ChannelBuffer * @param data the channel buffer to which we're serializing */ @Override public void writeTo(ChannelBuffer data) { if (bytes != null) data.writeBytes(bytes); } } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFVendorId.java0000664000175000017500000000551712041336206027272 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import java.util.HashMap; import java.util.Map; import org.jboss.netty.buffer.ChannelBuffer; /** * Base class for the vendor ID corresponding to vendor extensions from a * given vendor. It is responsible for knowing how to parse out some sort of * data type value from the vendor data in an OFVendor message so that we can * dispatch to the different subclasses of OFVendorData corresponding to the * different formats of data for the vendor extensions. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public abstract class OFVendorId { static Map mapping = new HashMap(); /** * The vendor id value, typically the OUI of the vendor prefixed with 0. */ protected int id; /** * Register a new vendor id. * @param vendorId the vendor id to register */ public static void registerVendorId(OFVendorId vendorId) { mapping.put(vendorId.getId(), vendorId); } /** * Lookup the OFVendorId instance corresponding to the given id value. * @param id the integer vendor id value * @return the corresponding OFVendorId that's been registered for the * given value, or null if there id has not been registered. */ public static OFVendorId lookupVendorId(int id) { return mapping.get(id); } /** * Create an OFVendorId with the give vendor id value * @param id */ public OFVendorId(int id) { this.id = id; } /** * @return the vendor id value */ public int getId() { return id; } /** * This function parses enough of the data from the channel buffer to be * able to determine the appropriate OFVendorDataType for the data. * * @param data the channel buffer containing the vendor data. * @param length the length to the end of the enclosing message * @return the OFVendorDataType that can be used to instantiate the * appropriate subclass of OFVendorData. */ public abstract OFVendorDataType parseVendorDataType(ChannelBuffer data, int length); } floodlight-0.90/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java0000664000175000017500000001413312041336206030226 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol.vendor; import java.util.HashMap; import java.util.Map; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.Instantiable; /** * Basic subclass of OFVendorId that works with any vendor data format where * the data begins with an integral data type value. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFBasicVendorId extends OFVendorId { /** * The size of the data type value at the beginning of all vendor * data associated with this vendor id. The data type size must be * either 1, 2, 4 or 8. */ protected int dataTypeSize; /** * Map of the vendor data types that have been registered for this * vendor id. */ protected Map dataTypeMap = new HashMap(); /** * Construct an OFVendorId that where the vendor data begins * with a data type value whose size is dataTypeSize. * @param id the id of the vendor, typically the OUI of a vendor * prefixed with 0. * @param dataTypeSize the size of the integral data type value * at the beginning of the vendor data. The value must be the * size of an integeral data type (i.e. either 1,2,4 or 8). */ public OFBasicVendorId(int id, int dataTypeSize) { super(id); assert (dataTypeSize == 1) || (dataTypeSize == 2) || (dataTypeSize == 4) || (dataTypeSize == 8); this.dataTypeSize = dataTypeSize; } /** * Get the size of the data type value at the beginning of the vendor * data. OFBasicVendorId assumes that this value is common across all of * the vendor data formats associated with a given vendor id. * @return */ public int getDataTypeSize() { return dataTypeSize; } /** * Register a vendor data type with this vendor id. * @param vendorDataType */ public void registerVendorDataType(OFBasicVendorDataType vendorDataType) { dataTypeMap.put(vendorDataType.getTypeValue(), vendorDataType); } /** * Lookup the OFVendorDataType instance that has been registered with * this vendor id. * * @param vendorDataType the integer code that was parsed from the * @return */ public OFVendorDataType lookupVendorDataType(int vendorDataType) { return dataTypeMap.get(vendorDataType); } /** * This function parses enough of the data from the buffer to be able * to determine the appropriate OFVendorDataType for the data. It is meant * to be a reasonably generic implementation that will work for most * formats of vendor extensions. If the vendor data doesn't fit the * assumptions listed below, then this method will need to be overridden * to implement custom parsing. * * This implementation assumes that the vendor data begins with a data * type code that is used to distinguish different formats of vendor * data associated with a particular vendor ID. * The exact format of the data is vendor-defined, so we don't know how * how big the code is (or really even if there is a code). This code * assumes that the common case will be that the data does include * an initial type code (i.e. so that the vendor can have multiple * message/data types) and that the size is either 1, 2 or 4 bytes. * The size of the initial type code is configured by the subclass of * OFVendorId. * * @param data the channel buffer containing the vendor data. * @param length the length to the end of the enclosing message * @return the OFVendorDataType that can be used to instantiate the * appropriate subclass of OFVendorData. */ public OFVendorDataType parseVendorDataType(ChannelBuffer data, int length) { OFVendorDataType vendorDataType = null; // Parse out the type code from the vendor data. long dataTypeValue = 0; if ((length == 0) || (length >= dataTypeSize)) { switch (dataTypeSize) { case 1: dataTypeValue = data.readByte(); break; case 2: dataTypeValue = data.readShort(); break; case 4: dataTypeValue = data.readInt(); break; case 8: dataTypeValue = data.readLong(); break; default: // This would be indicative of a coding error where the // dataTypeSize was specified incorrectly. This should have been // caught in the constructor for OFVendorId. assert false; } vendorDataType = dataTypeMap.get(dataTypeValue); } // If we weren't able to parse/map the data to a known OFVendorDataType, // then map it to a generic vendor data type. if (vendorDataType == null) { vendorDataType = new OFBasicVendorDataType(dataTypeValue, new Instantiable() { @Override public OFVendorData instantiate() { return new OFByteArrayVendorData(); } } ); } return vendorDataType; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFFeaturesReply.java0000664000175000017500000001503212041336206027046 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.ArrayList; import java.util.List; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.serializers.OFFeaturesReplyJSONSerializer; import org.openflow.util.U16; /** * Represents a features reply message * @author David Erickson (daviderickson@cs.stanford.edu) * */ @JsonSerialize(using=OFFeaturesReplyJSONSerializer.class) public class OFFeaturesReply extends OFMessage { public static int MINIMUM_LENGTH = 32; /** * Corresponds to bits on the capabilities field */ public enum OFCapabilities { OFPC_FLOW_STATS (1 << 0), OFPC_TABLE_STATS (1 << 1), OFPC_PORT_STATS (1 << 2), OFPC_STP (1 << 3), OFPC_RESERVED (1 << 4), OFPC_IP_REASM (1 << 5), OFPC_QUEUE_STATS (1 << 6), OFPC_ARP_MATCH_IP (1 << 7); protected int value; private OFCapabilities(int value) { this.value = value; } /** * @return the value */ public int getValue() { return value; } } protected long datapathId; protected int buffers; protected byte tables; protected int capabilities; protected int actions; protected List ports; public OFFeaturesReply() { super(); this.type = OFType.FEATURES_REPLY; this.length = U16.t(MINIMUM_LENGTH); } /** * @return the datapathId */ public long getDatapathId() { return datapathId; } /** * @param datapathId the datapathId to set */ public void setDatapathId(long datapathId) { this.datapathId = datapathId; } /** * @return the buffers */ public int getBuffers() { return buffers; } /** * @param buffers the buffers to set */ public void setBuffers(int buffers) { this.buffers = buffers; } /** * @return the tables */ public byte getTables() { return tables; } /** * @param tables the tables to set */ public void setTables(byte tables) { this.tables = tables; } /** * @return the capabilities */ public int getCapabilities() { return capabilities; } /** * @param capabilities the capabilities to set */ public void setCapabilities(int capabilities) { this.capabilities = capabilities; } /** * @return the actions */ public int getActions() { return actions; } /** * @param actions the actions to set */ public void setActions(int actions) { this.actions = actions; } /** * @return the ports */ public List getPorts() { return ports; } /** * @param ports the ports to set */ public void setPorts(List ports) { this.ports = ports; if (ports == null) { this.setLengthU(MINIMUM_LENGTH); } else { this.setLengthU(MINIMUM_LENGTH + ports.size() * OFPhysicalPort.MINIMUM_LENGTH); } } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.datapathId = data.readLong(); this.buffers = data.readInt(); this.tables = data.readByte(); data.readerIndex(data.readerIndex() + 3); // pad this.capabilities = data.readInt(); this.actions = data.readInt(); if (this.ports == null) { this.ports = new ArrayList(); } else { this.ports.clear(); } int portCount = (super.getLengthU() - 32) / OFPhysicalPort.MINIMUM_LENGTH; OFPhysicalPort port; for (int i = 0; i < portCount; ++i) { port = new OFPhysicalPort(); port.readFrom(data); this.ports.add(port); } } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeLong(this.datapathId); data.writeInt(this.buffers); data.writeByte(this.tables); data.writeShort((short) 0); // pad data.writeByte((byte) 0); // pad data.writeInt(this.capabilities); data.writeInt(this.actions); if (this.ports != null) for (OFPhysicalPort port : this.ports) { port.writeTo(data); } } @Override public int hashCode() { final int prime = 139; int result = super.hashCode(); result = prime * result + actions; result = prime * result + buffers; result = prime * result + capabilities; result = prime * result + (int) (datapathId ^ (datapathId >>> 32)); result = prime * result + ((ports == null) ? 0 : ports.hashCode()); result = prime * result + tables; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFFeaturesReply)) { return false; } OFFeaturesReply other = (OFFeaturesReply) obj; if (actions != other.actions) { return false; } if (buffers != other.buffers) { return false; } if (capabilities != other.capabilities) { return false; } if (datapathId != other.datapathId) { return false; } if (ports == null) { if (other.ports != null) { return false; } } else if (!ports.equals(other.ports)) { return false; } if (tables != other.tables) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFType.java0000664000175000017500000002240412041336206025176 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.lang.reflect.Constructor; /** * List of OpenFlow types and mappings to wire protocol value and derived * classes * * @author Rob Sherwood (rob.sherwood@stanford.edu) * @author David Erickson (daviderickson@cs.stanford.edu) * */ public enum OFType { HELLO (0, OFHello.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFHello(); }}), ERROR (1, OFError.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFError(); }}), ECHO_REQUEST (2, OFEchoRequest.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFEchoRequest(); }}), ECHO_REPLY (3, OFEchoReply.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFEchoReply(); }}), VENDOR (4, OFVendor.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFVendor(); }}), FEATURES_REQUEST (5, OFFeaturesRequest.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFFeaturesRequest(); }}), FEATURES_REPLY (6, OFFeaturesReply.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFFeaturesReply(); }}), GET_CONFIG_REQUEST (7, OFGetConfigRequest.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFGetConfigRequest(); }}), GET_CONFIG_REPLY (8, OFGetConfigReply.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFGetConfigReply(); }}), SET_CONFIG (9, OFSetConfig.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFSetConfig(); }}), PACKET_IN (10, OFPacketIn.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFPacketIn(); }}), FLOW_REMOVED (11, OFFlowRemoved.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFFlowRemoved(); }}), PORT_STATUS (12, OFPortStatus.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFPortStatus(); }}), PACKET_OUT (13, OFPacketOut.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFPacketOut(); }}), FLOW_MOD (14, OFFlowMod.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFFlowMod(); }}), PORT_MOD (15, OFPortMod.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFPortMod(); }}), STATS_REQUEST (16, OFStatisticsRequest.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFStatisticsRequest(); }}), STATS_REPLY (17, OFStatisticsReply.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFStatisticsReply(); }}), BARRIER_REQUEST (18, OFBarrierRequest.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFBarrierRequest(); }}), BARRIER_REPLY (19, OFBarrierReply.class, new Instantiable() { @Override public OFMessage instantiate() { return new OFBarrierReply(); }}); static OFType[] mapping; protected Class clazz; protected Constructor constructor; protected Instantiable instantiable; protected byte type; /** * Store some information about the OpenFlow type, including wire protocol * type number, length, and derived class * * @param type Wire protocol number associated with this OFType * @param clazz The Java class corresponding to this type of OpenFlow * message * @param instantiator An Instantiator implementation that creates an * instance of the specified OFMessage */ OFType(int type, Class clazz, Instantiable instantiator) { this.type = (byte) type; this.clazz = clazz; this.instantiable = instantiator; try { this.constructor = clazz.getConstructor(new Class[]{}); } catch (Exception e) { throw new RuntimeException( "Failure getting constructor for class: " + clazz, e); } OFType.addMapping(this.type, this); } /** * Adds a mapping from type value to OFType enum * * @param i OpenFlow wire protocol type * @param t type */ static public void addMapping(byte i, OFType t) { if (mapping == null) mapping = new OFType[32]; OFType.mapping[i] = t; } /** * Remove a mapping from type value to OFType enum * * @param i OpenFlow wire protocol type */ static public void removeMapping(byte i) { OFType.mapping[i] = null; } /** * Given a wire protocol OpenFlow type number, return the OFType associated * with it * * @param i wire protocol number * @return OFType enum type */ static public OFType valueOf(Byte i) { return OFType.mapping[i]; } /** * @return Returns the wire protocol value corresponding to this OFType */ public byte getTypeValue() { return this.type; } /** * @return return the OFMessage subclass corresponding to this OFType */ public Class toClass() { return clazz; } /** * Returns the no-argument Constructor of the implementation class for * this OFType * @return the constructor */ public Constructor getConstructor() { return constructor; } /** * Returns a new instance of the OFMessage represented by this OFType * @return the new object */ public OFMessage newInstance() { return instantiable.instantiate(); } /** * @return the instantiable */ public Instantiable getInstantiable() { return instantiable; } /** * @param instantiable the instantiable to set */ public void setInstantiable(Instantiable instantiable) { this.instantiable = instantiable; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPort.java0000664000175000017500000000246512041336206025206 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; public enum OFPort { OFPP_MAX ((short)0xff00), OFPP_IN_PORT ((short)0xfff8), OFPP_TABLE ((short)0xfff9), OFPP_NORMAL ((short)0xfffa), OFPP_FLOOD ((short)0xfffb), OFPP_ALL ((short)0xfffc), OFPP_CONTROLLER ((short)0xfffd), OFPP_LOCAL ((short)0xfffe), OFPP_NONE ((short)0xffff); protected short value; private OFPort(short value) { this.value = value; } /** * @return the value */ public short getValue() { return value; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFMatch.java0000664000175000017500000007535212041336206025323 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.Arrays; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.serializers.OFMatchJSONSerializer; import org.openflow.util.HexString; import org.openflow.util.U16; import org.openflow.util.U8; /** * Represents an ofp_match structure * * @author David Erickson (daviderickson@cs.stanford.edu) * @author Rob Sherwood (rob.sherwood@stanford.edu) * */ @JsonSerialize(using=OFMatchJSONSerializer.class) public class OFMatch implements Cloneable, Serializable { /** * */ private static final long serialVersionUID = 1L; public static int MINIMUM_LENGTH = 40; final public static int OFPFW_ALL = ((1 << 22) - 1); final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */ final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */ final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */ final public static int OFPFW_DL_DST = 1 << 3; /* * Ethernet destination * address. */ final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */ final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */ final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */ final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */ /* * IP source address wildcard bit count. 0 is exact match, 1 ignores the * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard * the entire field. This is the *opposite* of the usual convention where * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ final public static int OFPFW_NW_SRC_SHIFT = 8; final public static int OFPFW_NW_SRC_BITS = 6; final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT; final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT; /* IP destination address wildcard bit count. Same format as source. */ final public static int OFPFW_NW_DST_SHIFT = 14; final public static int OFPFW_NW_DST_BITS = 6; final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT; final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT; final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */ final public static int OFPFW_NW_TOS = 1 << 21; /* * IP ToS (DSCP field, 6 * bits). */ /* List of Strings for marshalling and unmarshalling to human readable forms */ final public static String STR_IN_PORT = "in_port"; final public static String STR_DL_DST = "dl_dst"; final public static String STR_DL_SRC = "dl_src"; final public static String STR_DL_TYPE = "dl_type"; final public static String STR_DL_VLAN = "dl_vlan"; final public static String STR_DL_VLAN_PCP = "dl_vlan_pcp"; final public static String STR_NW_DST = "nw_dst"; final public static String STR_NW_SRC = "nw_src"; final public static String STR_NW_PROTO = "nw_proto"; final public static String STR_NW_TOS = "nw_tos"; final public static String STR_TP_DST = "tp_dst"; final public static String STR_TP_SRC = "tp_src"; protected int wildcards; protected short inputPort; protected byte[] dataLayerSource; protected byte[] dataLayerDestination; protected short dataLayerVirtualLan; protected byte dataLayerVirtualLanPriorityCodePoint; protected short dataLayerType; protected byte networkTypeOfService; protected byte networkProtocol; protected int networkSource; protected int networkDestination; protected short transportSource; protected short transportDestination; /** * By default, create a OFMatch that matches everything * * (mostly because it's the least amount of work to make a valid OFMatch) */ public OFMatch() { this.wildcards = OFPFW_ALL; this.dataLayerDestination = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; this.dataLayerSource = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; this.dataLayerVirtualLan = -1; this.dataLayerVirtualLanPriorityCodePoint = 0; this.dataLayerType = 0; this.inputPort = 0; this.networkProtocol = 0; this.networkTypeOfService = 0; this.networkSource = 0; this.networkDestination = 0; this.transportDestination = 0; this.transportSource = 0; } /** * Get dl_dst * * @return an arrays of bytes */ public byte[] getDataLayerDestination() { return this.dataLayerDestination; } /** * Set dl_dst * * @param dataLayerDestination */ public OFMatch setDataLayerDestination(byte[] dataLayerDestination) { this.dataLayerDestination = dataLayerDestination; return this; } /** * Set dl_dst, but first translate to byte[] using HexString * * @param mac * A colon separated string of 6 pairs of octets, e..g., * "00:17:42:EF:CD:8D" */ public OFMatch setDataLayerDestination(String mac) { byte bytes[] = HexString.fromHexString(mac); if (bytes.length != 6) throw new IllegalArgumentException( "expected string with 6 octets, got '" + mac + "'"); this.dataLayerDestination = bytes; return this; } /** * Get dl_src * * @return an array of bytes */ public byte[] getDataLayerSource() { return this.dataLayerSource; } /** * Set dl_src * * @param dataLayerSource */ public OFMatch setDataLayerSource(byte[] dataLayerSource) { this.dataLayerSource = dataLayerSource; return this; } /** * Set dl_src, but first translate to byte[] using HexString * * @param mac * A colon separated string of 6 pairs of octets, e..g., * "00:17:42:EF:CD:8D" */ public OFMatch setDataLayerSource(String mac) { byte bytes[] = HexString.fromHexString(mac); if (bytes.length != 6) throw new IllegalArgumentException( "expected string with 6 octets, got '" + mac + "'"); this.dataLayerSource = bytes; return this; } /** * Get dl_type * * @return ether_type */ public short getDataLayerType() { return this.dataLayerType; } /** * Set dl_type * * @param dataLayerType */ public OFMatch setDataLayerType(short dataLayerType) { this.dataLayerType = dataLayerType; return this; } /** * Get dl_vlan * * @return vlan tag; VLAN_NONE == no tag */ public short getDataLayerVirtualLan() { return this.dataLayerVirtualLan; } /** * Set dl_vlan * * @param dataLayerVirtualLan */ public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) { this.dataLayerVirtualLan = dataLayerVirtualLan; return this; } /** * Get dl_vlan_pcp * * @return */ public byte getDataLayerVirtualLanPriorityCodePoint() { return this.dataLayerVirtualLanPriorityCodePoint; } /** * Set dl_vlan_pcp * * @param pcp */ public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) { this.dataLayerVirtualLanPriorityCodePoint = pcp; return this; } /** * Get in_port * * @return */ public short getInputPort() { return this.inputPort; } /** * Set in_port * * @param inputPort */ public OFMatch setInputPort(short inputPort) { this.inputPort = inputPort; return this; } /** * Get nw_dst * * @return */ public int getNetworkDestination() { return this.networkDestination; } /** * Set nw_dst * * @param networkDestination */ public OFMatch setNetworkDestination(int networkDestination) { this.networkDestination = networkDestination; return this; } /** * Parse this match's wildcard fields and return the number of significant * bits in the IP destination field. * * NOTE: this returns the number of bits that are fixed, i.e., like CIDR, * not the number of bits that are free like OpenFlow encodes. * * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact * match) */ public int getNetworkDestinationMaskLen() { return Math .max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT), 0); } /** * Parse this match's wildcard fields and return the number of significant * bits in the IP destination field. * * NOTE: this returns the number of bits that are fixed, i.e., like CIDR, * not the number of bits that are free like OpenFlow encodes. * * @return a number between 0 (matches all IPs) and 32 (exact match) */ public int getNetworkSourceMaskLen() { return Math .max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT), 0); } /** * Get nw_proto * * @return */ public byte getNetworkProtocol() { return this.networkProtocol; } /** * Set nw_proto * * @param networkProtocol */ public OFMatch setNetworkProtocol(byte networkProtocol) { this.networkProtocol = networkProtocol; return this; } /** * Get nw_src * * @return */ public int getNetworkSource() { return this.networkSource; } /** * Set nw_src * * @param networkSource */ public OFMatch setNetworkSource(int networkSource) { this.networkSource = networkSource; return this; } /** * Get nw_tos * OFMatch stores the ToS bits as top 6-bits, so right shift by 2 bits * before returning the value * * @return : 6-bit DSCP value (0-63) */ public byte getNetworkTypeOfService() { return (byte) ((this.networkTypeOfService >> 2) & 0x3f); } /** * Set nw_tos * OFMatch stores the ToS bits as top 6-bits, so left shift by 2 bits * before storing the value * * @param networkTypeOfService : 6-bit DSCP value (0-63) */ public OFMatch setNetworkTypeOfService(byte networkTypeOfService) { this.networkTypeOfService = (byte)(networkTypeOfService << 2); return this; } /** * Get tp_dst * * @return */ public short getTransportDestination() { return this.transportDestination; } /** * Set tp_dst * * @param transportDestination */ public OFMatch setTransportDestination(short transportDestination) { this.transportDestination = transportDestination; return this; } /** * Get tp_src * * @return */ public short getTransportSource() { return this.transportSource; } /** * Set tp_src * * @param transportSource */ public OFMatch setTransportSource(short transportSource) { this.transportSource = transportSource; return this; } /** * Get wildcards * * @return */ public int getWildcards() { return this.wildcards; } /** * Set wildcards * * @param wildcards */ public OFMatch setWildcards(int wildcards) { this.wildcards = wildcards; return this; } /** * Initializes this OFMatch structure with the corresponding data from the * specified packet. * * Must specify the input port, to ensure that this.in_port is set * correctly. * * Specify OFPort.NONE or OFPort.ANY if input port not applicable or * available * * @param packetData * The packet's data * @param inputPort * the port the packet arrived on */ public OFMatch loadFromPacket(byte[] packetData, short inputPort) { short scratch; int transportOffset = 34; ByteBuffer packetDataBB = ByteBuffer.wrap(packetData); int limit = packetDataBB.limit(); this.wildcards = 0; // all fields have explicit entries this.inputPort = inputPort; if (inputPort == OFPort.OFPP_ALL.getValue()) this.wildcards |= OFPFW_IN_PORT; assert (limit >= 14); // dl dst this.dataLayerDestination = new byte[6]; packetDataBB.get(this.dataLayerDestination); // dl src this.dataLayerSource = new byte[6]; packetDataBB.get(this.dataLayerSource); // dl type this.dataLayerType = packetDataBB.getShort(); if (getDataLayerType() != (short) 0x8100) { // need cast to avoid signed // bug setDataLayerVirtualLan((short) 0xffff); setDataLayerVirtualLanPriorityCodePoint((byte) 0); } else { // has vlan tag scratch = packetDataBB.getShort(); setDataLayerVirtualLan((short) (0xfff & scratch)); setDataLayerVirtualLanPriorityCodePoint((byte) ((0xe000 & scratch) >> 13)); this.dataLayerType = packetDataBB.getShort(); } switch (getDataLayerType()) { case 0x0800: // ipv4 // check packet length scratch = packetDataBB.get(); scratch = (short) (0xf & scratch); transportOffset = (packetDataBB.position() - 1) + (scratch * 4); // nw tos (dscp) scratch = packetDataBB.get(); setNetworkTypeOfService((byte) ((0xfc & scratch) >> 2)); // nw protocol packetDataBB.position(packetDataBB.position() + 7); this.networkProtocol = packetDataBB.get(); // nw src packetDataBB.position(packetDataBB.position() + 2); this.networkSource = packetDataBB.getInt(); // nw dst this.networkDestination = packetDataBB.getInt(); packetDataBB.position(transportOffset); break; case 0x0806: // arp int arpPos = packetDataBB.position(); // opcode scratch = packetDataBB.getShort(arpPos + 6); setNetworkProtocol((byte) (0xff & scratch)); scratch = packetDataBB.getShort(arpPos + 2); // if ipv4 and addr len is 4 if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) { // nw src this.networkSource = packetDataBB.getInt(arpPos + 14); // nw dst this.networkDestination = packetDataBB.getInt(arpPos + 24); } else { setNetworkSource(0); setNetworkDestination(0); } break; default: setNetworkTypeOfService((byte) 0); setNetworkProtocol((byte) 0); setNetworkSource(0); setNetworkDestination(0); break; } switch (getNetworkProtocol()) { case 0x01: // icmp // type this.transportSource = U8.f(packetDataBB.get()); // code this.transportDestination = U8.f(packetDataBB.get()); break; case 0x06: // tcp // tcp src this.transportSource = packetDataBB.getShort(); // tcp dest this.transportDestination = packetDataBB.getShort(); break; case 0x11: // udp // udp src this.transportSource = packetDataBB.getShort(); // udp dest this.transportDestination = packetDataBB.getShort(); break; default: setTransportDestination((short) 0); setTransportSource((short) 0); break; } return this; } /** * Read this message off the wire from the specified ByteBuffer * * @param data */ public void readFrom(ChannelBuffer data) { this.wildcards = data.readInt(); this.inputPort = data.readShort(); this.dataLayerSource = new byte[6]; data.readBytes(this.dataLayerSource); this.dataLayerDestination = new byte[6]; data.readBytes(this.dataLayerDestination); this.dataLayerVirtualLan = data.readShort(); this.dataLayerVirtualLanPriorityCodePoint = data.readByte(); data.readByte(); // pad this.dataLayerType = data.readShort(); this.networkTypeOfService = data.readByte(); this.networkProtocol = data.readByte(); data.readByte(); // pad data.readByte(); // pad this.networkSource = data.readInt(); this.networkDestination = data.readInt(); this.transportSource = data.readShort(); this.transportDestination = data.readShort(); } /** * Write this message's binary format to the specified ByteBuffer * * @param data */ public void writeTo(ChannelBuffer data) { data.writeInt(wildcards); data.writeShort(inputPort); data.writeBytes(this.dataLayerSource); data.writeBytes(this.dataLayerDestination); data.writeShort(dataLayerVirtualLan); data.writeByte(dataLayerVirtualLanPriorityCodePoint); data.writeByte((byte) 0x0); // pad data.writeShort(dataLayerType); data.writeByte(networkTypeOfService); data.writeByte(networkProtocol); data.writeByte((byte) 0x0); // pad data.writeByte((byte) 0x0); // pad data.writeInt(networkSource); data.writeInt(networkDestination); data.writeShort(transportSource); data.writeShort(transportDestination); } @Override public int hashCode() { final int prime = 131; int result = 1; result = prime * result + Arrays.hashCode(dataLayerDestination); result = prime * result + Arrays.hashCode(dataLayerSource); result = prime * result + dataLayerType; result = prime * result + dataLayerVirtualLan; result = prime * result + dataLayerVirtualLanPriorityCodePoint; result = prime * result + inputPort; result = prime * result + networkDestination; result = prime * result + networkProtocol; result = prime * result + networkSource; result = prime * result + networkTypeOfService; result = prime * result + transportDestination; result = prime * result + transportSource; result = prime * result + wildcards; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFMatch)) { return false; } OFMatch other = (OFMatch) obj; if (!Arrays.equals(dataLayerDestination, other.dataLayerDestination)) { return false; } if (!Arrays.equals(dataLayerSource, other.dataLayerSource)) { return false; } if (dataLayerType != other.dataLayerType) { return false; } if (dataLayerVirtualLan != other.dataLayerVirtualLan) { return false; } if (dataLayerVirtualLanPriorityCodePoint != other.dataLayerVirtualLanPriorityCodePoint) { return false; } if (inputPort != other.inputPort) { return false; } if (networkDestination != other.networkDestination) { return false; } if (networkProtocol != other.networkProtocol) { return false; } if (networkSource != other.networkSource) { return false; } if (networkTypeOfService != other.networkTypeOfService) { return false; } if (transportDestination != other.transportDestination) { return false; } if (transportSource != other.transportSource) { return false; } if ((wildcards & OFMatch.OFPFW_ALL) != (other.wildcards & OFPFW_ALL)) { // only // consider // allocated // part // of // wildcards return false; } return true; } /** * Implement clonable interface */ @Override public OFMatch clone() { try { OFMatch ret = (OFMatch) super.clone(); ret.dataLayerDestination = this.dataLayerDestination.clone(); ret.dataLayerSource = this.dataLayerSource.clone(); return ret; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } /** * Output a dpctl-styled string, i.e., only list the elements that are not * wildcarded * * A match-everything OFMatch outputs "OFMatch[]" * * @return * "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]" */ @Override public String toString() { String str = ""; // l1 if ((wildcards & OFPFW_IN_PORT) == 0) str += "," + STR_IN_PORT + "=" + U16.f(this.inputPort); // l2 if ((wildcards & OFPFW_DL_DST) == 0) str += "," + STR_DL_DST + "=" + HexString.toHexString(this.dataLayerDestination); if ((wildcards & OFPFW_DL_SRC) == 0) str += "," + STR_DL_SRC + "=" + HexString.toHexString(this.dataLayerSource); if ((wildcards & OFPFW_DL_TYPE) == 0) str += "," + STR_DL_TYPE + "=0x" + Integer.toHexString(U16.f(this.dataLayerType)); if ((wildcards & OFPFW_DL_VLAN) == 0) str += "," + STR_DL_VLAN + "=0x" + Integer.toHexString(U16.f(this.dataLayerVirtualLan)); if ((wildcards & OFPFW_DL_VLAN_PCP) == 0) str += "," + STR_DL_VLAN_PCP + "=" + Integer.toHexString(U8 .f(this.dataLayerVirtualLanPriorityCodePoint)); // l3 if (getNetworkDestinationMaskLen() > 0) str += "," + STR_NW_DST + "=" + cidrToString(networkDestination, getNetworkDestinationMaskLen()); if (getNetworkSourceMaskLen() > 0) str += "," + STR_NW_SRC + "=" + cidrToString(networkSource, getNetworkSourceMaskLen()); if ((wildcards & OFPFW_NW_PROTO) == 0) str += "," + STR_NW_PROTO + "=" + this.networkProtocol; if ((wildcards & OFPFW_NW_TOS) == 0) str += "," + STR_NW_TOS + "=" + this.getNetworkTypeOfService(); // l4 if ((wildcards & OFPFW_TP_DST) == 0) str += "," + STR_TP_DST + "=" + this.transportDestination; if ((wildcards & OFPFW_TP_SRC) == 0) str += "," + STR_TP_SRC + "=" + this.transportSource; if ((str.length() > 0) && (str.charAt(0) == ',')) str = str.substring(1); // trim the leading "," // done return "OFMatch[" + str + "]"; } private String cidrToString(int ip, int prefix) { String str; if (prefix >= 32) { str = ipToString(ip); } else { // use the negation of mask to fake endian magic int mask = ~((1 << (32 - prefix)) - 1); str = ipToString(ip & mask) + "/" + prefix; } return str; } /** * Set this OFMatch's parameters based on a comma-separated key=value pair * dpctl-style string, e.g., from the output of OFMatch.toString()
*

* Supported keys/values include
*

* * * * * * * * * * * * * *
KEY(s) * VALUE *
"in_port","input_port" * integer *
"dl_src","eth_src", "dl_dst","eth_dst" * hex-string *
"dl_type", "dl_vlan", "dl_vlan_pcp" * integer *
"nw_src", "nw_dst", "ip_src", "ip_dst" * CIDR-style netmask *
"tp_src","tp_dst" * integer (max 64k) *
*

* The CIDR-style netmasks assume 32 netmask if none given, so: * "128.8.128.118/32" is the same as "128.8.128.118" * * @param match * a key=value comma separated string, e.g. * "in_port=5,ip_dst=192.168.0.0/16,tp_src=80" * @throws IllegalArgumentException * on unexpected key or value */ public void fromString(String match) throws IllegalArgumentException { if (match.equals("") || match.equalsIgnoreCase("any") || match.equalsIgnoreCase("all") || match.equals("[]")) match = "OFMatch[]"; String[] tokens = match.split("[\\[,\\]]"); String[] values; int initArg = 0; if (tokens[0].equals("OFMatch")) initArg = 1; this.wildcards = OFPFW_ALL; int i; for (i = initArg; i < tokens.length; i++) { values = tokens[i].split("="); if (values.length != 2) throw new IllegalArgumentException("Token " + tokens[i] + " does not have form 'key=value' parsing " + match); values[0] = values[0].toLowerCase(); // try to make this case insens if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) { this.inputPort = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_IN_PORT; } else if (values[0].equals(STR_DL_DST) || values[0].equals("eth_dst")) { this.dataLayerDestination = HexString.fromHexString(values[1]); this.wildcards &= ~OFPFW_DL_DST; } else if (values[0].equals(STR_DL_SRC) || values[0].equals("eth_src")) { this.dataLayerSource = HexString.fromHexString(values[1]); this.wildcards &= ~OFPFW_DL_SRC; } else if (values[0].equals(STR_DL_TYPE) || values[0].equals("eth_type")) { if (values[1].startsWith("0x")) this.dataLayerType = U16.t(Integer.valueOf( values[1].replaceFirst("0x", ""), 16)); else this.dataLayerType = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_DL_TYPE; } else if (values[0].equals(STR_DL_VLAN)) { if (values[1].startsWith("0x")) this.dataLayerVirtualLan = U16.t(Integer.valueOf( values[1].replaceFirst("0x", ""),16)); else this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_DL_VLAN; } else if (values[0].equals(STR_DL_VLAN_PCP)) { this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short .valueOf(values[1])); this.wildcards &= ~OFPFW_DL_VLAN_PCP; } else if (values[0].equals(STR_NW_DST) || values[0].equals("ip_dst")) { setFromCIDR(values[1], STR_NW_DST); } else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src")) { setFromCIDR(values[1], STR_NW_SRC); } else if (values[0].equals(STR_NW_PROTO)) { this.networkProtocol = U8.t(Short.valueOf(values[1])); this.wildcards &= ~OFPFW_NW_PROTO; } else if (values[0].equals(STR_NW_TOS)) { this.setNetworkTypeOfService(U8.t(Short.valueOf(values[1]))); this.wildcards &= ~OFPFW_NW_TOS; } else if (values[0].equals(STR_TP_DST)) { this.transportDestination = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_TP_DST; } else if (values[0].equals(STR_TP_SRC)) { this.transportSource = U16.t(Integer.valueOf(values[1])); this.wildcards &= ~OFPFW_TP_SRC; } else { throw new IllegalArgumentException("unknown token " + tokens[i] + " parsing " + match); } } } /** * Set the networkSource or networkDestionation address and their wildcards * from the CIDR string * * @param cidr * "192.168.0.0/16" or "172.16.1.5" * @param which * one of STR_NW_DST or STR_NW_SRC * @throws IllegalArgumentException */ private void setFromCIDR(String cidr, String which) throws IllegalArgumentException { String values[] = cidr.split("/"); String[] ip_str = values[0].split("\\."); int ip = 0; ip += Integer.valueOf(ip_str[0]) << 24; ip += Integer.valueOf(ip_str[1]) << 16; ip += Integer.valueOf(ip_str[2]) << 8; ip += Integer.valueOf(ip_str[3]); int prefix = 32; // all bits are fixed, by default if (values.length >= 2) prefix = Integer.valueOf(values[1]); int mask = 32 - prefix; if (which.equals(STR_NW_DST)) { this.networkDestination = ip; this.wildcards = (wildcards & ~OFPFW_NW_DST_MASK) | (mask << OFPFW_NW_DST_SHIFT); } else if (which.equals(STR_NW_SRC)) { this.networkSource = ip; this.wildcards = (wildcards & ~OFPFW_NW_SRC_MASK) | (mask << OFPFW_NW_SRC_SHIFT); } } protected static String ipToString(int ip) { return Integer.toString(U8.f((byte) ((ip & 0xff000000) >> 24))) + "." + Integer.toString((ip & 0x00ff0000) >> 16) + "." + Integer.toString((ip & 0x0000ff00) >> 8) + "." + Integer.toString(ip & 0x000000ff); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFStatisticsReply.java0000664000175000017500000000251512041336206027424 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an ofp_stats_reply message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFStatisticsReply extends OFStatisticsMessageBase { public enum OFStatisticsReplyFlags { REPLY_MORE (1 << 0); protected short type; OFStatisticsReplyFlags(int type) { this.type = (short) type; } public short getTypeValue() { return type; } } public OFStatisticsReply() { super(); this.type = OFType.STATS_REPLY; this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java0000664000175000017500000000703612041336206026717 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.beans.SimpleBeanInfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.LinkedList; import java.util.List; /** * Extra info for how to treat OFMatch as a JavaBean * * For some (inane!) reason, using chained setters in OFMatch breaks a lot of the JavaBean defaults. * * We don't really use OFMatch as a java bean, but there are a lot of nice XML utils that work for * free if OFMatch follows the java bean paradigm. * * @author Rob Sherwood (rob.sherwood@stanford.edu) * */ public class OFMatchBeanInfo extends SimpleBeanInfo { @Override public PropertyDescriptor[] getPropertyDescriptors() { List descs = new LinkedList(); Field[] fields = OFMatch.class.getDeclaredFields(); String name; for (int i=0; i< fields.length; i++) { int mod = fields[i].getModifiers(); if(Modifier.isFinal(mod) || // don't expose static or final fields Modifier.isStatic(mod)) continue; name = fields[i].getName(); Class type = fields[i].getType(); try { descs.add(new PropertyDescriptor(name, name2getter(OFMatch.class, name), name2setter(OFMatch.class, name, type))); } catch (IntrospectionException e) { e.printStackTrace(); throw new RuntimeException(e); } } return descs.toArray(new PropertyDescriptor[0]); } private Method name2setter(Class c, String name, Class type) { String mName = "set" + toLeadingCaps(name); Method m = null; try { m = c.getMethod(mName, new Class[]{ type}); } catch (SecurityException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (NoSuchMethodException e) { e.printStackTrace(); throw new RuntimeException(e); } return m; } private Method name2getter(Class c, String name) { String mName= "get" + toLeadingCaps(name); Method m = null; try { m = c.getMethod(mName, new Class[]{}); } catch (SecurityException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (NoSuchMethodException e) { e.printStackTrace(); throw new RuntimeException(e); } return m; } private String toLeadingCaps(String s) { char[] array = s.toCharArray(); array[0] = Character.toUpperCase(array[0]); return String.valueOf(array, 0, array.length); } } floodlight-0.90/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java0000664000175000017500000000162412041336206027261 0ustar jamespagejamespagepackage org.openflow.protocol; import org.openflow.util.HexString; public class OFMatchWithSwDpid { protected OFMatch ofMatch; protected long switchDataPathId; public OFMatchWithSwDpid() { this.ofMatch = new OFMatch(); this.switchDataPathId = 0; } public OFMatchWithSwDpid(OFMatch ofm, long swDpid) { this.ofMatch = ofm.clone(); this.switchDataPathId = swDpid; } public OFMatch getOfMatch() { return ofMatch; } public void setOfMatch(OFMatch ofMatch) { this.ofMatch = ofMatch.clone(); } public long getSwitchDataPathId() { return this.switchDataPathId; } public OFMatchWithSwDpid setSwitchDataPathId(long dpid) { this.switchDataPathId = dpid; return this; } @Override public String toString() { return "OFMatchWithSwDpid [" + HexString.toHexString(switchDataPathId) + ofMatch + "]"; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFFlowRemoved.java0000664000175000017500000001650712041336206026515 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * Represents an ofp_flow_removed message * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class OFFlowRemoved extends OFMessage { public static int MINIMUM_LENGTH = 88; public enum OFFlowRemovedReason { OFPRR_IDLE_TIMEOUT, OFPRR_HARD_TIMEOUT, OFPRR_DELETE } protected OFMatch match; protected long cookie; protected short priority; protected OFFlowRemovedReason reason; protected int durationSeconds; protected int durationNanoseconds; protected short idleTimeout; protected long packetCount; protected long byteCount; public OFFlowRemoved() { super(); this.type = OFType.FLOW_REMOVED; this.length = U16.t(MINIMUM_LENGTH); } /** * Get cookie * @return */ public long getCookie() { return this.cookie; } /** * Set cookie * @param cookie */ public void setCookie(long cookie) { this.cookie = cookie; } /** * Get idle_timeout * @return */ public short getIdleTimeout() { return this.idleTimeout; } /** * Set idle_timeout * @param idleTimeout */ public void setIdleTimeout(short idleTimeout) { this.idleTimeout = idleTimeout; } /** * Gets a copy of the OFMatch object for this FlowMod, changes to this * object do not modify the FlowMod * @return */ public OFMatch getMatch() { return this.match; } /** * Set match * @param match */ public void setMatch(OFMatch match) { this.match = match; } /** * Get priority * @return */ public short getPriority() { return this.priority; } /** * Set priority * @param priority */ public void setPriority(short priority) { this.priority = priority; } /** * @return the reason */ public OFFlowRemovedReason getReason() { return reason; } /** * @param reason the reason to set */ public void setReason(OFFlowRemovedReason reason) { this.reason = reason; } /** * @return the durationSeconds */ public int getDurationSeconds() { return durationSeconds; } /** * @param durationSeconds the durationSeconds to set */ public void setDurationSeconds(int durationSeconds) { this.durationSeconds = durationSeconds; } /** * @return the durationNanoseconds */ public int getDurationNanoseconds() { return durationNanoseconds; } /** * @param durationNanoseconds the durationNanoseconds to set */ public void setDurationNanoseconds(int durationNanoseconds) { this.durationNanoseconds = durationNanoseconds; } /** * @return the packetCount */ public long getPacketCount() { return packetCount; } /** * @param packetCount the packetCount to set */ public void setPacketCount(long packetCount) { this.packetCount = packetCount; } /** * @return the byteCount */ public long getByteCount() { return byteCount; } /** * @param byteCount the byteCount to set */ public void setByteCount(long byteCount) { this.byteCount = byteCount; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); if (this.match == null) this.match = new OFMatch(); this.match.readFrom(data); this.cookie = data.readLong(); this.priority = data.readShort(); this.reason = OFFlowRemovedReason.values()[(0xff & data.readByte())]; data.readByte(); // pad this.durationSeconds = data.readInt(); this.durationNanoseconds = data.readInt(); this.idleTimeout = data.readShort(); data.readByte(); // pad data.readByte(); // pad this.packetCount = data.readLong(); this.byteCount = data.readLong(); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); this.match.writeTo(data); data.writeLong(cookie); data.writeShort(priority); data.writeByte((byte) this.reason.ordinal()); data.writeByte((byte) 0); data.writeInt(this.durationSeconds); data.writeInt(this.durationNanoseconds); data.writeShort(idleTimeout); data.writeByte((byte) 0); // pad data.writeByte((byte) 0); // pad data.writeLong(this.packetCount); data.writeLong(this.byteCount); } @Override public int hashCode() { final int prime = 271; int result = super.hashCode(); result = prime * result + (int) (byteCount ^ (byteCount >>> 32)); result = prime * result + (int) (cookie ^ (cookie >>> 32)); result = prime * result + durationNanoseconds; result = prime * result + durationSeconds; result = prime * result + idleTimeout; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + (int) (packetCount ^ (packetCount >>> 32)); result = prime * result + priority; result = prime * result + ((reason == null) ? 0 : reason.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFFlowRemoved)) { return false; } OFFlowRemoved other = (OFFlowRemoved) obj; if (byteCount != other.byteCount) { return false; } if (cookie != other.cookie) { return false; } if (durationNanoseconds != other.durationNanoseconds) { return false; } if (durationSeconds != other.durationSeconds) { return false; } if (idleTimeout != other.idleTimeout) { return false; } if (match == null) { if (other.match != null) { return false; } } else if (!match.equals(other.match)) { return false; } if (packetCount != other.packetCount) { return false; } if (priority != other.priority) { return false; } if (reason == null) { if (other.reason != null) { return false; } } else if (!reason.equals(other.reason)) { return false; } return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFPacketIn.java0000664000175000017500000001224712041336206025757 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; import org.openflow.util.U32; import org.openflow.util.U8; /** * Represents an ofp_packet_in * * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010 */ public class OFPacketIn extends OFMessage { public static short MINIMUM_LENGTH = 18; public enum OFPacketInReason { NO_MATCH, ACTION } protected int bufferId; protected short totalLength; protected short inPort; protected OFPacketInReason reason; protected byte[] packetData; public OFPacketIn() { super(); this.type = OFType.PACKET_IN; this.length = U16.t(MINIMUM_LENGTH); } /** * Get buffer_id * @return */ public int getBufferId() { return this.bufferId; } /** * Set buffer_id * @param bufferId */ public OFPacketIn setBufferId(int bufferId) { this.bufferId = bufferId; return this; } /** * Returns the packet data * @return */ public byte[] getPacketData() { return this.packetData; } /** * Sets the packet data, and updates the length of this message * @param packetData */ public OFPacketIn setPacketData(byte[] packetData) { this.packetData = packetData; this.length = U16.t(OFPacketIn.MINIMUM_LENGTH + packetData.length); return this; } /** * Get in_port * @return */ public short getInPort() { return this.inPort; } /** * Set in_port * @param inPort */ public OFPacketIn setInPort(short inPort) { this.inPort = inPort; return this; } /** * Get reason * @return */ public OFPacketInReason getReason() { return this.reason; } /** * Set reason * @param reason */ public OFPacketIn setReason(OFPacketInReason reason) { this.reason = reason; return this; } /** * Get total_len * @return */ public short getTotalLength() { return this.totalLength; } /** * Set total_len * @param totalLength */ public OFPacketIn setTotalLength(short totalLength) { this.totalLength = totalLength; return this; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.bufferId = data.readInt(); this.totalLength = data.readShort(); this.inPort = data.readShort(); this.reason = OFPacketInReason.values()[U8.f(data.readByte())]; data.readByte(); // pad this.packetData = new byte[getLengthU() - MINIMUM_LENGTH]; data.readBytes(this.packetData); } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(bufferId); data.writeShort(totalLength); data.writeShort(inPort); data.writeByte((byte) reason.ordinal()); data.writeByte((byte) 0x0); // pad data.writeBytes(this.packetData); } @Override public int hashCode() { final int prime = 283; int result = super.hashCode(); result = prime * result + bufferId; result = prime * result + inPort; result = prime * result + Arrays.hashCode(packetData); result = prime * result + ((reason == null) ? 0 : reason.hashCode()); result = prime * result + totalLength; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof OFPacketIn)) { return false; } OFPacketIn other = (OFPacketIn) obj; if (bufferId != other.bufferId) { return false; } if (inPort != other.inPort) { return false; } if (!Arrays.equals(packetData, other.packetData)) { return false; } if (reason == null) { if (other.reason != null) { return false; } } else if (!reason.equals(other.reason)) { return false; } if (totalLength != other.totalLength) { return false; } return true; } public String toString() { String myStr = super.toString(); return "packetIn" + ":bufferId=" + U32.f(this.bufferId) + myStr; } } floodlight-0.90/src/main/java/org/openflow/protocol/OFError.java0000664000175000017500000002207412041336206025351 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.factory.MessageParseException; import org.openflow.protocol.factory.OFMessageFactory; import org.openflow.protocol.factory.OFMessageFactoryAware; import org.openflow.util.U16; /** * Represents an ofp_error_msg * * @author David Erickson (daviderickson@cs.stanford.edu) * @author Rob Sherwood (rob.sherwood@stanford.edu) */ public class OFError extends OFMessage implements OFMessageFactoryAware { public static int MINIMUM_LENGTH = 12; public enum OFErrorType { // OFPET_VENDOR_ERROR is an extension that was added in Open vSwitch and isn't // in the OF 1.0 spec, but it was easier to add it here instead of adding // generic support for extensible vendor-defined error messages. // It uses the random value 0xb0c2 to avoid conflicts with other possible new // error types. Support for vendor-defined extended errors has been standardized // in the OF 1.2 spec, so this workaround is only needed for 1.0. OFPET_HELLO_FAILED, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_FLOW_MOD_FAILED, OFPET_PORT_MOD_FAILED, OFPET_QUEUE_OP_FAILED, OFPET_VENDOR_ERROR((short)0xb0c2); protected short value; private OFErrorType() { this.value = (short) this.ordinal(); } private OFErrorType(short value) { this.value = value; } public short getValue() { return value; } } public enum OFHelloFailedCode { OFPHFC_INCOMPATIBLE, OFPHFC_EPERM } public enum OFBadRequestCode { OFPBRC_BAD_VERSION, OFPBRC_BAD_TYPE, OFPBRC_BAD_STAT, OFPBRC_BAD_VENDOR, OFPBRC_BAD_SUBTYPE, OFPBRC_EPERM, OFPBRC_BAD_LEN, OFPBRC_BUFFER_EMPTY, OFPBRC_BUFFER_UNKNOWN } public enum OFBadActionCode { OFPBAC_BAD_TYPE, OFPBAC_BAD_LEN, OFPBAC_BAD_VENDOR, OFPBAC_BAD_VENDOR_TYPE, OFPBAC_BAD_OUT_PORT, OFPBAC_BAD_ARGUMENT, OFPBAC_EPERM, OFPBAC_TOO_MANY, OFPBAC_BAD_QUEUE } public enum OFFlowModFailedCode { OFPFMFC_ALL_TABLES_FULL, OFPFMFC_OVERLAP, OFPFMFC_EPERM, OFPFMFC_BAD_EMERG_TIMEOUT, OFPFMFC_BAD_COMMAND, OFPFMFC_UNSUPPORTED } public enum OFPortModFailedCode { OFPPMFC_BAD_PORT, OFPPMFC_BAD_HW_ADDR } public enum OFQueueOpFailedCode { OFPQOFC_BAD_PORT, OFPQOFC_BAD_QUEUE, OFPQOFC_EPERM } protected short errorType; protected short errorCode; protected int vendor; protected int vendorErrorType; protected short vendorErrorCode; protected OFMessageFactory factory; protected byte[] error; protected boolean errorIsAscii; public OFError() { super(); this.type = OFType.ERROR; this.length = U16.t(MINIMUM_LENGTH); } /** * @return the errorType */ public short getErrorType() { return errorType; } /** * @param errorType * the errorType to set */ public void setErrorType(short errorType) { this.errorType = errorType; } public void setErrorType(OFErrorType type) { this.errorType = type.getValue(); } /** * @return true if the error is an extended vendor error */ public boolean isVendorError() { return errorType == OFErrorType.OFPET_VENDOR_ERROR.getValue(); } /** * @return the errorCode */ public short getErrorCode() { return errorCode; } /** * @param errorCode * the errorCode to set */ public void setErrorCode(OFHelloFailedCode code) { this.errorCode = (short) code.ordinal(); } public void setErrorCode(short errorCode) { this.errorCode = errorCode; } public void setErrorCode(OFBadRequestCode code) { this.errorCode = (short) code.ordinal(); } public void setErrorCode(OFBadActionCode code) { this.errorCode = (short) code.ordinal(); } public void setErrorCode(OFFlowModFailedCode code) { this.errorCode = (short) code.ordinal(); } public void setErrorCode(OFPortModFailedCode code) { this.errorCode = (short) code.ordinal(); } public void setErrorCode(OFQueueOpFailedCode code) { this.errorCode = (short) code.ordinal(); } public int getVendorErrorType() { return vendorErrorType; } public void setVendorErrorType(int vendorErrorType) { this.vendorErrorType = vendorErrorType; } public short getVendorErrorCode() { return vendorErrorCode; } public void setVendorErrorCode(short vendorErrorCode) { this.vendorErrorCode = vendorErrorCode; } public OFMessage getOffendingMsg() throws MessageParseException { // should only have one message embedded; if more than one, just // grab first if (this.error == null) return null; ChannelBuffer errorMsg = ChannelBuffers.wrappedBuffer(this.error); if (factory == null) throw new RuntimeException("MessageFactory not set"); List msglist = this.factory.parseMessage(errorMsg); if (msglist == null) return null; return msglist.get(0); } /** * Write this offending message into the payload of the Error message * * @param offendingMsg */ public void setOffendingMsg(OFMessage offendingMsg) { if (offendingMsg == null) { super.setLengthU(MINIMUM_LENGTH); } else { this.error = new byte[offendingMsg.getLengthU()]; ChannelBuffer data = ChannelBuffers.wrappedBuffer(this.error); data.writerIndex(0); offendingMsg.writeTo(data); super.setLengthU(MINIMUM_LENGTH + offendingMsg.getLengthU()); } } public OFMessageFactory getFactory() { return factory; } @Override public void setMessageFactory(OFMessageFactory factory) { this.factory = factory; } /** * @return the error */ public byte[] getError() { return error; } /** * @param error * the error to set */ public void setError(byte[] error) { this.error = error; } /** * @return the errorIsAscii */ public boolean isErrorIsAscii() { return errorIsAscii; } /** * @param errorIsAscii * the errorIsAscii to set */ public void setErrorIsAscii(boolean errorIsAscii) { this.errorIsAscii = errorIsAscii; } @Override public void readFrom(ChannelBuffer data) { super.readFrom(data); this.errorType = data.readShort(); this.errorCode = data.readShort(); int dataLength = this.getLengthU() - MINIMUM_LENGTH; if (dataLength > 0) { this.error = new byte[dataLength]; data.readBytes(this.error); if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.getValue()) this.errorIsAscii = true; } } @Override public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(errorType); data.writeShort(errorCode); if (error != null) data.writeBytes(error); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(error); result = prime * result + errorCode; result = prime * result + (errorIsAscii ? 1231 : 1237); result = prime * result + errorType; return result; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OFError other = (OFError) obj; if (!Arrays.equals(error, other.error)) return false; if (errorCode != other.errorCode) return false; if (errorIsAscii != other.errorIsAscii) return false; if (errorType != other.errorType) return false; return true; } } floodlight-0.90/src/main/java/org/openflow/protocol/Instantiable.java0000664000175000017500000000165612041336206026453 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public interface Instantiable { /** * Create a new instance of a given subclass. * @return the new instance. */ public E instantiate(); } floodlight-0.90/src/main/java/org/openflow/protocol/OFGetConfigRequest.java0000664000175000017500000000206012041336206027467 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.openflow.util.U16; /** * Represents an OFPT_GET_CONFIG_REQUEST type message * @author David Erickson (daviderickson@cs.stanford.edu) */ public class OFGetConfigRequest extends OFMessage { public OFGetConfigRequest() { super(); this.type = OFType.GET_CONFIG_REQUEST; this.length = U16.t(OFMessage.MINIMUM_LENGTH); } } floodlight-0.90/src/main/java/org/openflow/vendor/0000775000175000017500000000000012041336206022617 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/vendor/nicira/0000775000175000017500000000000012041336206024064 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java0000664000175000017500000000416312041336206031045 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.vendor.nicira; import org.openflow.protocol.Instantiable; import org.openflow.protocol.vendor.OFVendorData; /** * Subclass of OFVendorData representing the vendor data associated with * a role reply vendor extension. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFRoleReplyVendorData extends OFRoleVendorData { protected static Instantiable instantiable = new Instantiable() { public OFVendorData instantiate() { return new OFRoleReplyVendorData(); } }; /** * @return a subclass of Instantiable that instantiates * an instance of OFRoleReplyVendorData. */ public static Instantiable getInstantiable() { return instantiable; } /** * The data type value for a role reply */ public static final int NXT_ROLE_REPLY = 11; /** * Construct a role reply vendor data with an unspecified role value. */ public OFRoleReplyVendorData() { super(NXT_ROLE_REPLY); } /** * Construct a role reply vendor data with the specified role value. * @param role the role value for the role reply. Should be one of * NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE. */ public OFRoleReplyVendorData(int role) { super(NXT_ROLE_REPLY, role); } } floodlight-0.90/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java0000664000175000017500000000421512041336206031400 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.vendor.nicira; import org.openflow.protocol.Instantiable; import org.openflow.protocol.vendor.OFVendorData; /** * Subclass of OFVendorData representing the vendor data associated with * a role request vendor extension. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFRoleRequestVendorData extends OFRoleVendorData { protected static Instantiable instantiable = new Instantiable() { public OFVendorData instantiate() { return new OFRoleRequestVendorData(); } }; /** * @return a subclass of Instantiable that instantiates * an instance of OFRoleRequestVendorData. */ public static Instantiable getInstantiable() { return instantiable; } /** * The data type value for a role request */ public static final int NXT_ROLE_REQUEST = 10; /** * Construct a role request vendor data with an unspecified role value. */ public OFRoleRequestVendorData() { super(NXT_ROLE_REQUEST); } /** * Construct a role request vendor data with the specified role value. * @param role the role value for the role request. Should be one of * NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE. */ public OFRoleRequestVendorData(int role) { super(NXT_ROLE_REQUEST, role); } } floodlight-0.90/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java0000664000175000017500000000603012041336206030330 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.vendor.nicira; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.protocol.vendor.OFVendorData; /** * Base class for vendor data corresponding to a Nicira vendor extension. * Nicira vendor data always starts with a 4-byte integer data type value. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFNiciraVendorData implements OFVendorData { public static final int NX_VENDOR_ID = 0x00002320; /** * The value of the integer data type at the beginning of the vendor data */ protected int dataType; /** * Construct empty (i.e. unspecified data type) Nicira vendor data. */ public OFNiciraVendorData() { } /** * Contruct Nicira vendor data with the specified data type * @param dataType the data type value at the beginning of the vendor data. */ public OFNiciraVendorData(int dataType) { this.dataType = dataType; } /** * Get the data type value at the beginning of the vendor data * @return the integer data type value */ public int getDataType() { return dataType; } /** * Set the data type value * @param dataType the integer data type value at the beginning of the * vendor data. */ public void setDataType(int dataType) { this.dataType = dataType; } /** * Get the length of the vendor data. This implementation will normally * be the superclass for another class that will override this to return * the overall vendor data length. This implementation just returns the * length of the part that includes the 4-byte integer data type value * at the beginning of the vendor data. */ @Override public int getLength() { return 4; } /** * Read the vendor data from the ChannelBuffer * @param data the channel buffer from which we're deserializing * @param length the length to the end of the enclosing message */ @Override public void readFrom(ChannelBuffer data, int length) { dataType = data.readInt(); } /** * Write the vendor data to the ChannelBuffer * @param data the channel buffer to which we're serializing */ @Override public void writeTo(ChannelBuffer data) { data.writeInt(dataType); } } floodlight-0.90/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java0000664000175000017500000000627012041336206030032 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson & Rob Sherwood, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.vendor.nicira; import org.jboss.netty.buffer.ChannelBuffer; /** * Class that represents the vendor data in the role request * extension implemented by Open vSwitch to support high availability. * * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com) */ public class OFRoleVendorData extends OFNiciraVendorData { /** * Role value indicating that the controller is in the OTHER role. */ public static final int NX_ROLE_OTHER = 0; /** * Role value indicating that the controller is in the MASTER role. */ public static final int NX_ROLE_MASTER = 1; /** * Role value indicating that the controller is in the SLAVE role. */ public static final int NX_ROLE_SLAVE = 2; protected int role; /** * Construct an uninitialized OFRoleVendorData */ public OFRoleVendorData() { super(); } /** * Construct an OFRoleVendorData with the specified data type * (i.e. either request or reply) and an unspecified role. * @param dataType */ public OFRoleVendorData(int dataType) { super(dataType); } /** * Construct an OFRoleVendorData with the specified data type * (i.e. either request or reply) and role (i.e. one of of * master, slave, or other). * @param dataType either role request or role reply data type */ public OFRoleVendorData(int dataType, int role) { super(dataType); this.role = role; } /** * @return the role value of the role vendor data */ public int getRole() { return role; } /** * @param role the role value of the role vendor data */ public void setRole(int role) { this.role = role; } /** * @return the total length of the role vendor data */ @Override public int getLength() { return super.getLength() + 4; } /** * Read the role vendor data from the ChannelBuffer * @param data the channel buffer from which we're deserializing * @param length the length to the end of the enclosing message */ public void readFrom(ChannelBuffer data, int length) { super.readFrom(data, length); role = data.readInt(); } /** * Write the role vendor data to the ChannelBuffer * @param data the channel buffer to which we're serializing */ public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeInt(role); } } floodlight-0.90/src/main/java/org/openflow/util/0000775000175000017500000000000012041336206022277 5ustar jamespagejamespagefloodlight-0.90/src/main/java/org/openflow/util/U64.java0000664000175000017500000000165212041336206023524 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.math.BigInteger; public class U64 { public static BigInteger f(long i) { return new BigInteger(Long.toBinaryString(i), 2); } public static long t(BigInteger l) { return l.longValue(); } } floodlight-0.90/src/main/java/org/openflow/util/U16.java0000664000175000017500000000154212041336206023517 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; public class U16 { public static int f(short i) { return (int)i & 0xffff; } public static short t(int l) { return (short) l; } } floodlight-0.90/src/main/java/org/openflow/util/U8.java0000664000175000017500000000155412041336206023443 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; public class U8 { public static short f(byte i) { return (short) ((short)i & 0xff); } public static byte t(short l) { return (byte) l; } } floodlight-0.90/src/main/java/org/openflow/util/LRULinkedHashMap.java0000664000175000017500000000260112041336206026174 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.util.LinkedHashMap; public class LRULinkedHashMap extends LinkedHashMap { private static final long serialVersionUID = -2964986094089626647L; protected int maximumCapacity; public LRULinkedHashMap(int initialCapacity, int maximumCapacity) { super(initialCapacity, 0.75f, true); this.maximumCapacity = maximumCapacity; } public LRULinkedHashMap(int maximumCapacity) { super(16, 0.75f, true); this.maximumCapacity = maximumCapacity; } @Override protected boolean removeEldestEntry(java.util.Map.Entry eldest) { if (this.size() > maximumCapacity) return true; return false; } } floodlight-0.90/src/main/java/org/openflow/util/U32.java0000664000175000017500000000154412041336206023517 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; public class U32 { public static long f(int i) { return (long)i & 0xffffffffL; } public static int t(long l) { return (int) l; } } floodlight-0.90/src/main/java/org/openflow/util/HexString.java0000664000175000017500000000572012041336206025061 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.math.BigInteger; public class HexString { /** * Convert a string of bytes to a ':' separated hex string * @param bytes * @return "0f:ca:fe:de:ad:be:ef" */ public static String toHexString(byte[] bytes) { int i; String ret = ""; String tmp; for(i=0; i< bytes.length; i++) { if(i> 0) ret += ":"; tmp = Integer.toHexString(U8.f(bytes[i])); if (tmp.length() == 1) ret += "0"; ret += tmp; } return ret; } public static String toHexString(long val, int padTo) { char arr[] = Long.toHexString(val).toCharArray(); String ret = ""; // prepend the right number of leading zeros int i = 0; for (; i < (padTo * 2 - arr.length); i++) { ret += "0"; if ((i % 2) == 1) ret += ":"; } for (int j = 0; j < arr.length; j++) { ret += arr[j]; if ((((i + j) % 2) == 1) && (j < (arr.length - 1))) ret += ":"; } return ret; } public static String toHexString(long val) { return toHexString(val, 8); } /** * Convert a string of hex values into a string of bytes * @param values "0f:ca:fe:de:ad:be:ef" * @return [15, 5 ,2, 5, 17] * @throws NumberFormatException If the string can not be parsed */ public static byte[] fromHexString(String values) throws NumberFormatException { String[] octets = values.split(":"); byte[] ret = new byte[octets.length]; for(int i = 0; i < octets.length; i++) { if (octets[i].length() > 2) throw new NumberFormatException("Invalid octet length"); ret[i] = Integer.valueOf(octets[i], 16).byteValue(); } return ret; } public static long toLong(String values) throws NumberFormatException { // Long.parseLong() can't handle HexStrings with MSB set. Sigh. BigInteger bi = new BigInteger(values.replaceAll(":", ""),16); if (bi.bitLength() > 64) throw new NumberFormatException("Input string too big to fit in long: " + values); return bi.longValue(); } } floodlight-0.90/src/main/java/org/openflow/util/Unsigned.java0000664000175000017500000001536312041336206024726 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.math.BigInteger; import java.nio.ByteBuffer; /***** * A util library class for dealing with the lack of unsigned datatypes in Java * * @author Rob Sherwood (rob.sherwood@stanford.edu) * @author David Erickson (daviderickson@cs.stanford.edu) */ public class Unsigned { /** * Get an unsigned byte from the current position of the ByteBuffer * * @param bb ByteBuffer to get the byte from * @return an unsigned byte contained in a short */ public static short getUnsignedByte(ByteBuffer bb) { return ((short) (bb.get() & (short) 0xff)); } /** * Get an unsigned byte from the specified offset in the ByteBuffer * * @param bb ByteBuffer to get the byte from * @param offset the offset to get the byte from * @return an unsigned byte contained in a short */ public static short getUnsignedByte(ByteBuffer bb, int offset) { return ((short) (bb.get(offset) & (short) 0xff)); } /** * Put an unsigned byte into the specified ByteBuffer at the current * position * * @param bb ByteBuffer to put the byte into * @param v the short containing the unsigned byte */ public static void putUnsignedByte(ByteBuffer bb, short v) { bb.put((byte) (v & 0xff)); } /** * Put an unsigned byte into the specified ByteBuffer at the specified * offset * * @param bb ByteBuffer to put the byte into * @param v the short containing the unsigned byte * @param offset the offset to insert the unsigned byte at */ public static void putUnsignedByte(ByteBuffer bb, short v, int offset) { bb.put(offset, (byte) (v & 0xff)); } /** * Get an unsigned short from the current position of the ByteBuffer * * @param bb ByteBuffer to get the byte from * @return an unsigned short contained in a int */ public static int getUnsignedShort(ByteBuffer bb) { return (bb.getShort() & 0xffff); } /** * Get an unsigned short from the specified offset in the ByteBuffer * * @param bb ByteBuffer to get the short from * @param offset the offset to get the short from * @return an unsigned short contained in a int */ public static int getUnsignedShort(ByteBuffer bb, int offset) { return (bb.getShort(offset) & 0xffff); } /** * Put an unsigned short into the specified ByteBuffer at the current * position * * @param bb ByteBuffer to put the short into * @param v the int containing the unsigned short */ public static void putUnsignedShort(ByteBuffer bb, int v) { bb.putShort((short) (v & 0xffff)); } /** * Put an unsigned short into the specified ByteBuffer at the specified * offset * * @param bb ByteBuffer to put the short into * @param v the int containing the unsigned short * @param offset the offset to insert the unsigned short at */ public static void putUnsignedShort(ByteBuffer bb, int v, int offset) { bb.putShort(offset, (short) (v & 0xffff)); } /** * Get an unsigned int from the current position of the ByteBuffer * * @param bb ByteBuffer to get the int from * @return an unsigned int contained in a long */ public static long getUnsignedInt(ByteBuffer bb) { return ((long) bb.getInt() & 0xffffffffL); } /** * Get an unsigned int from the specified offset in the ByteBuffer * * @param bb ByteBuffer to get the int from * @param offset the offset to get the int from * @return an unsigned int contained in a long */ public static long getUnsignedInt(ByteBuffer bb, int offset) { return ((long) bb.getInt(offset) & 0xffffffffL); } /** * Put an unsigned int into the specified ByteBuffer at the current position * * @param bb ByteBuffer to put the int into * @param v the long containing the unsigned int */ public static void putUnsignedInt(ByteBuffer bb, long v) { bb.putInt((int) (v & 0xffffffffL)); } /** * Put an unsigned int into the specified ByteBuffer at the specified offset * * @param bb ByteBuffer to put the int into * @param v the long containing the unsigned int * @param offset the offset to insert the unsigned int at */ public static void putUnsignedInt(ByteBuffer bb, long v, int offset) { bb.putInt(offset, (int) (v & 0xffffffffL)); } /** * Get an unsigned long from the current position of the ByteBuffer * * @param bb ByteBuffer to get the long from * @return an unsigned long contained in a BigInteger */ public static BigInteger getUnsignedLong(ByteBuffer bb) { byte[] v = new byte[8]; for (int i = 0; i < 8; ++i) { v[i] = bb.get(i); } return new BigInteger(1, v); } /** * Get an unsigned long from the specified offset in the ByteBuffer * * @param bb ByteBuffer to get the long from * @param offset the offset to get the long from * @return an unsigned long contained in a BigInteger */ public static BigInteger getUnsignedLong(ByteBuffer bb, int offset) { byte[] v = new byte[8]; for (int i = 0; i < 8; ++i) { v[i] = bb.get(offset+i); } return new BigInteger(1, v); } /** * Put an unsigned long into the specified ByteBuffer at the current * position * * @param bb ByteBuffer to put the long into * @param v the BigInteger containing the unsigned long */ public static void putUnsignedLong(ByteBuffer bb, BigInteger v) { bb.putLong(v.longValue()); } /** * Put an unsigned long into the specified ByteBuffer at the specified * offset * * @param bb ByteBuffer to put the long into * @param v the BigInteger containing the unsigned long * @param offset the offset to insert the unsigned long at */ public static void putUnsignedLong(ByteBuffer bb, BigInteger v, int offset) { bb.putLong(offset, v.longValue()); } } floodlight-0.90/src/main/java/org/openflow/util/StringByteSerializer.java0000664000175000017500000000357612041336206027301 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Arrays; import org.jboss.netty.buffer.ChannelBuffer; public class StringByteSerializer { public static String readFrom(ChannelBuffer data, int length) { byte[] stringBytes = new byte[length]; data.readBytes(stringBytes); // find the first index of 0 int index = 0; for (byte b : stringBytes) { if (0 == b) break; ++index; } return new String(Arrays.copyOf(stringBytes, index), Charset.forName("ascii")); } public static void writeTo(ChannelBuffer data, int length, String value) { try { byte[] name = value.getBytes("ASCII"); if (name.length < length) { data.writeBytes(name); for (int i = name.length; i < length; ++i) { data.writeByte((byte) 0); } } else { data.writeBytes(name, 0, length-1); data.writeByte((byte) 0); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } } floodlight-0.90/src/main/images/0000775000175000017500000000000012041336206017226 5ustar jamespagejamespagefloodlight-0.90/src/main/images/Floodlight Icons.sketch/0000775000175000017500000000000012041336206023635 5ustar jamespagejamespagefloodlight-0.90/src/main/images/Floodlight Icons.sketch/Data0000664000175000017500000021623312041336206024440 0ustar jamespagejamespagebplist00X$versionX$objectsY$archiverT$top\!KU\]w{8"(,26789?KLMNTYabcdjptu'./<?CMNT^dhnrx|}~   &'()/37;NSTadhrsy  &'()./09:;<BKLMNTZl{|}~ $+,9<@JKQ[aekouyz{~#$%&,048EJWZ^hioy $%&/0128ABCDJNX`abcklmnvwxy   $.48>BHLMNOWXYZ`hijkquv}     ! % & ' * . : ; A K Q U [ _ e i j k l t u v w }            % * : @ A N Q U _ ` f p v z         & ' ( ) / 8 9 : ; A E I M Z ^ k n r | }      ' ( ) * 0 1 2 3 8 9 : C D E F L U V W X ^ b l t | } ~         ( ) / 9 ? C I M S W X Y Z b c d e k s t u v | "&,01259EFLV\`fjptuvw  !$*/4DKLY\`jkq{ !&'(1234:CDEFLPTXeijwz~  $%,3456<=>?DEFOPQRXabcdjnt|}~   %/59?CIMNOPXYZ[aijklrvw~ $*./037CDJTZ^dhnrstu}~ &06:@DJNOPSWcdjtz~  !"#+,-.56:<?EJO_efsvz  !(/01289:;@ABKLMNT]^_`fjnr  !"(01239=>ELMNOUVWX]^_hijkqz{|}%)/39=>?BFRSYcimsw}"%)34:DJNTX^bcdgkwx~  !/4ADHRSYcimsw} "+,-.48@HIJKSTUV^_`abfhkqv{ "#$%-./06>?@AGKLSZ[\]cdefklmvwxy!'+15;?@ABJKLMS[\]^dhipwxyz #./1<=?BHIOQUY[`ekoquxz~U$null [layerStylesUpages_currentPageIndex_expandedListItemStore^bitmapLayerIDs_ shouldMirrorDrawingAtRulerOrigin_layerNameCounterV$classZtextStyles\masterLayersS WY [P_ [NS.object.0"#$%&'()*+,-./0123456789:;<=66@A6C6EFG66J_isFlippedHorizontalUstyleXrotation_horizontalRulerDataUframeYartboardsYzoomValueVslicesWisCloneVlocked_verticalRulerData_isFlippedVertical^layerContainer[nameIsFixedTnameTgrid\scrollOrigin_shouldBreakMaskChainXisSymbolWvisibleHE"A9OK]MG LMNOP88QRJTQxQyUwidth_constrainProportionsVheight VWXYZ$classnameX$classesVMSRectZ[VMSRectXNSObjectVPage 1^_`abcdefghijklmnopqrstuv]borderOptionsYouterGlow_contextSettingsYinnerGlow[shadowStyleTblurUfillsZreflectionZmiterLimit_innerShadowStyle]colorControlsWborders=O;V\/AK 5FxyzUarray |} [NS.object.0 `0XpositionYthicknessUcolorYisEnabledXfillTypeXgradient   VBorderQaQbQrQg"?"?P"?P"?PVW_MSArchivedColor[_MSArchivedColor866StoY\gradientType_shouldSmoothenOpacityUfromYZhasChangedUstopsStoX\elipseLengthUfromX"?""?""? [NS.object.0[NS.object.1""?"?"?"?VW^MSGradientStop[^MSGradientStop"?"?"""VW^NSMutableArray[WNSArrayVWZMSGradient[ZMSGradientYblendModeWopacity #?VW_MSGraphicsContextSettings[_MSGraphicsContextSettings\MSDataObject#?VW]MSStyleBorder[]MSStyleBorder_MSStyleBasicFill[MSStylePartVW[MSDataArray[[MSDataArray\MSDataObjectxy [NS.object.0 `0_patternFillType\patternImage^noiseIntensity_patternTileScale -*#.! ,"$TFill    "?"?X"?X"?X866"?"%"?""? [NS.object.0[NS.object.1&( "'#$%'"?"?"?"?)*"?)-./1"?"""4܀ +#?#?#VW:;[MSStyleFill<=>[[MSStyleFill_MSStyleBasicFill[MSStylePart@ABCDFGHJZblurRadiusYhasShadowWoffsetYWoffsetX2 134 0##@#@OPQS"?"""VWUV]MSStyleShadowWX[]MSStyleShadow[MSStylePart@ABCZ\]^`8 79: 6##?#@efgi"?"""VWkl_MSStyleInnerShadowmno[_MSStyleInnerShadow]MSStyleShadow[MSStylePartr܀ <#?vwxy|~^hasDashPattern\lineCapStyle[dashPattern]lineJoinStyle > @ ?VW[VW_MSStyleBorderOptions[_MSStyleBorderOptions[MSStylePartVradius[motionAngleTtypeVcenterBC E D#@$#Z{0.5, 0.5}VW[MSStyleBlur[[MSStyleBlur[MSStylePartZsaturationZbrightnessXcontrastJ GHI#?##?VW_MSStyleColorControls[_MSStyleColorControls[MSStylePartXstrengthXdistanceLN M#?#?VW_MSStyleReflection[_MSStyleReflection[MSStylePart@ABCTsizeR QSTU P###@"?""?"?VW_MSStyleOuterGlow[_MSStyleOuterGlow]MSStyleShadow[MSStylePart@ABC݀Y XZT[ W###@"?""?"?VW_MSStyleInnerGlow[_MSStyleInnerGlow_MSStyleOuterGlow]MSStyleShadow[MSStylePartVWWMSStyle[WMSStyleVlayersZidentifier^8ZfirstArray[secondArray_`     [NS.object.6[NS.object.7[NS.object.0[NS.object.1[NS.object.2[NS.object.3[NS.object.4[NS.object.54a]3#$&-."*+5/06866866"6J86&^artisticStroke_hasClippingMask_endDecorationTypeYpathStyle_startDecorationTypedb cLMNOP()*RJ- @  [Rectangle 1^_`abcdefghi0123n5678s9:;\sexy>f@A [NS.object.0g`0EFGKL!rpi! hjVBorderOPQS"?"?P"?P"?PU86W6Z[\]"?"k"?""?_`a c[NS.object.0[NS.object.1lnef"mijkm"?"?"?"?op"?ostuw"?"""z܀ q#?#@xyt [NS.object.0u`0 ~w.! vxTFill"?"?X"?X"?X866"?"y"?""? [NS.object.0[NS.object.1z|"{"?"?"?"?"?}"?"""܀ #?#?#@ABCHʀ 4 ##@#@"?"""@ABC^ۀ : ##?#@"?"""܀ #?vwxy|~ > @  E #@$#Z{0.5, 0.5}J #?##?N #?#?@ABC  TU ###@"?""?"?@ABC !% T[ ###@*+,."?""?"?02689 [NS.object.03#$<&-=>?"+5/06A86C6EFGH66J6MVedited_booleanOperation[fixedRadiusTpath LMNOP88OR6R@ TPath^_`abcdefghiUVWXnZ[\]s^_`ԀҀ\ȀՀ݀̀ـxycef [NS.object.0`0jklpq!! VBordertuvx"?"?P"?P"?Pz86|6"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?xy [NS.object.0`0 ǀĀ.! ƀTFill"?"?X"?X"?X866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?À"?"""܀ ŀ#?#?#@ABCHˀ ʀ̀4 ##@#@"?"""@ABC^Ѐ πр: ##?#@ "?""" ܀ Ӏ#?vwxy|~ > @ ր׀ E #@$#Z{0.5, 0.5}#$%J ڀۀ#?##?*-ހN #?#?@ABC1348 TU ###@=>?A"?""?"?@ABCCEFJ T[ ###@OPQS"?""?"?UVWXJVpointsXisClosed [\]^_`abcde ghijk[NS.object.6[NS.object.7[NS.object.0[NS.object.1[NS.object.2[NS.object.3[NS.object.4[NS.object.5 mnopqrsJuvJFxyz\hasCurveFromScp1ZhasCurveToYcurveModeUpointScp2\cornerRadius Z{0, 0.125}[{0, 0.0625}Z{0, 0.125}VW\MSCurvePoint[\MSCurvePointmnopqrsJvJF Z{0, 0.875}Z{0, 0.875}[{0, 0.9375}mnopqrsJvJF [{0.0625, 1}\{0.03125, 1}[{0.0625, 1}mnopqrsJvJF [{0.9375, 1}[{0.9375, 1}\{0.96875, 1}mnopqrsJvJF Z{1, 0.875}[{1, 0.9375}Z{1, 0.875}mnopqrsJvJF  Z{1, 0.125}Z{1, 0.125}[{1, 0.0625}mnopqrsJvJF  [{0.9375, 0}\{0.96875, 0}[{0.9375, 0}mnopqrsJvJF    [{0.0625, 0}[{0.0625, 0}\{0.03125, 0}VW[MSShapePath[[MSShapePathVW_MSRectangleShape[_MSRectangleShape_MSCustomShapeLayer_MSShapePathLayerWMSLayerVW_MSMultipleMutableArray[_MSMultipleMutableArray{VW_MSLayerContainer[_MSLayerContainer\MSDataObject0[decorations VW_MSPathDecorationStyle[_MSPathDecorationStyleWhandles [NS.object.0[NS.object.1[rightHandle^positionOnPathZleftHandle"""VW_MSArtisticStrokeHandle[_MSArtisticStrokeHandle ""?"VW  _MSArtisticStroke [_MSArtisticStrokeVW\MSShapeGroup[\MSShapeGroup\MSLayerGroupWMSLayer3#$&-."*+5/068668666J86#_ LMNOP%&'R6*>>VOval 2^_`abcdefghi-./0n2345s678IUGZ\=J.RBN xy;!=> [NS.object.0"`0BCDHI -+$! #%VBorderLMNP"?"?P"?P"?PR86T6WXYZ"?"&"?""?\]^ `[NS.object.0[NS.object.1')bc"(fghj"?"?"?"?lm"?*pqrt"?"""w܀ ,#?#@xy}/ [NS.object.00`0 <92.! ;13TFill"?"?X"?X"?X866"?"4"?""? [NS.object.0[NS.object.157"6"?"?"?"?"?8"?"""܀ :#?#?#@ABCHǁ@ ?A4 >##@#@"?"""@ABC^؁E DF: C##?#@"?"""܀ H#?vwxy|~ > @ KL E M#@$#Z{0.5, 0.5}J OPQ#?##?SN T#?#?@ABC   X WYTU V###@"?""?"?@ABC"] \^T[ [###@'()+"?""?"?-/`3a56 [NS.object.0b3#$<&-=?"+5/06:86<6E>?66J6Mdc LMNOP88FR6I>>^_`abcdefghiKLMNnPQRSsTUV\sexyYf[\ [NS.object.0g`0`abfg rpi! hjVBorderjkln"?"?P"?P"?Pp86r6uvwx"?"k"?""?z{| ~[NS.object.0[NS.object.1ln"m"?"?"?"?"?o"?"""܀ q#?#?xyt [NS.object.0u`0 ~w.! vxTFill"?"?X"?X"?X866"?"y"?""? [NS.object.0[NS.object.1z|"{"?"?"?"?"?}"?"""܀ #?#?#@ABCH 4 ##@#@"?"""@ABC^ : ##?#@"?"""܀ #?vwxy|~ > @   E #@$#Z{0.5, 0.5}J #?##? #N #?#?@ABC')*. TU ###@3457"?""?"?@ABC9;<@ T[ ###@EFGI"?""?"?UVKXJ OPQRS UVW[NS.object.0[NS.object.1[NS.object.2[NS.object.3mnopqrsJZvJ]^_  X{0.5, 1}]{0.223858, 1}]{0.776142, 1}mnopqrsJevJhij  X{1, 0.5}]{1, 0.776142}]{1, 0.223858}mnopqrsJpvJstu  X{0.5, 0}]{0.776142, 0}]{0.223858, 0}mnopqrsJ{vJ~  X{0, 0.5}]{0, 0.223858}]{0, 0.776142}VW[MSOvalShape[[MSOvalShape_MSShapePathLayerWMSLayerU0  [NS.object.0[NS.object.1"""""?"3#$&-."*+5/068668666J86YW LMNOPFR6&[Rectangle 3^_`abcdefghinsǁ\߁Ёxyʀ [NS.object.0Ā`0؀!ρ́ƀ ŁVBorder"?"?P"?P"?P866"?""?""? [NS.object.0[NS.object.1ɀ"ʀ"?"?"?"?"?̀"?"""܀ ΀#?#?xy  [NS.object.0Ҁ`0 ށہԀ.! ݁ӁTFill !#"?"? y"? "? ķ%86'6*+,-"?""?""?/01 3[NS.object.0[NS.object.1׀56"؀9:;="?"?"?"??@"?ڀCDEG"?"""J܀ ܀#?#?#@ABCPRSHV 4 ##@#@[\]_"?"""@ABCacd^g : ##?#@lmnp"?"""s܀ #?vwxy|~ > @ ~ E #@$#Z{0.5, 0.5}J #?##?N #?#?@ABC TU ###@"?""?"?@ABC T[ ###@"?""?"?V€ [NS.object.03#$<&-=>?"+5/06866E8H66J6MF LMNOP88FR6׀^_`abcdefghins0<.A\$19)5xy [NS.object.0 `0! !   VBorder"?"?P"?P"?P86 6    "?" "?""?  [NS.object.0[NS.object.1  "    "?"?"?"?  "?    "?""" #܀ #?#?xy ) + , [NS.object.0`0 1 2 3 7 8 9 # .! "TFill < = > @"?"?X"?X"?X B86 D6 G H I J"?""?""? L M N P[NS.object.0[NS.object.1 R S" V W X Z"?"?"?"? \ ]"? ` a b d"?""" g܀ !#?#?#@ABC m o pH s' &(4 %##@#@ x y z |"?"""@ABC ~ ^ , +-: *##?#@ "?""" ܀ /#?vwxy|~ > @   23 E 4#@$#Z{0.5, 0.5} J 678#?##?  :N ;#?#?@ABC   ? >@TU =###@ "?""?"?@ABC   ΁D CET[ B###@ "?""?"?UV XJG  [NS.object.0[NS.object.1[NS.object.2[NS.object.3HJNRmnopqrs6 v6 IIIV{0, 0}mnopqrs6 v6 LKMV{0, 1}V{0, 1}V{0, 1}mnopqrs6 v6 POQV{1, 1}V{1, 1}V{1, 1}mnopqrs6 v6 TSUV{1, 0}V{1, 0}V{1, 0}$0 X  Z    [NS.object.0[NS.object.1[\ ! " $""" & ' )""?"3#$&-."*+5/06 ,8 - .668 166 56J86 9`^ _LMNOP ; <FR6 ?&[Rectangle 3^_`abcdefghi B C D En G H I Js K L M\~oaxy Pb R S [NS.object.0c`0 W X Y ] ^!nle dfVBorder a b c e"?"?P"?P"?P g86 i6 l m n o"?"g"?""? q r s u[NS.object.0[NS.object.1hj w x"i { | } "?"?"?"? "?k "?""" ܀ m#?#?xy p  [NS.object.0q`0  }zs.! |rtTFill "?"? y"? "? ķ 86 6 "?"u"?""?  [NS.object.0[NS.object.1vx "w "?"?"?"? "?y "?""" ܀ {#?#?#@ABC  H ܁ 4 ##@#@ "?"""@ABC  ^  : ##?#@ "?""" ܀ #?vwxy|~ > @     E #@$#Z{0.5, 0.5}   J #?##?  N #?#?@ABC  ! % TU ###@ * + , ."?""?"?@ABC 0 2 3 7 T[ ###@ < = > @"?""?"? B D H J K [NS.object.03#$<&-=>?"+5/06 O86 Q6E8 SH66J6M LMNOP88FR6 ]^_`abcdefghi _ ` a bn d e f gs h i jρہ́\ÁЁ؁ȁԁxy m o p [NS.object.0`0 t u v z {!! VBorder ~  "?"?P"?P"?P 86 6 "?""?""?  [NS.object.0[NS.object.1 " "?"?"?"? "? "?""" ܀ #?#?xy   [NS.object.0`0  .! TFill "?"?X"?X"?X 86 6 "?""?""?  [NS.object.0[NS.object.1 " "?"?"?"? "? "?""" ܀ #?#?#@ABC  H ƀ Łǀ4 ##@#@ "?"""@ABC   ^ ˀ ʁ̀: ##?#@    "?""" ܀ ΀#?vwxy|~ > @  ! " &сҀ E #@$#Z{0.5, 0.5} - . /J Ձց#?##? 4 7ـN #?#?@ABC ; = > Bހ ݁߀TU ###@ G H I K"?""?"?@ABC M O P T T[ ###@ Y Z [ ]"?""?"?UV _XJ c d e f g i j k[NS.object.0[NS.object.1[NS.object.2[NS.object.3mnopqrs6 v6 sIIImnopqrs6 vv6 y z {V{0, 1}V{0, 1}V{0, 1}mnopqrs6 v6 V{1, 1}V{1, 1}V{1, 1}mnopqrs6 v6 V{1, 0}V{1, 0}V{1, 0}$0     [NS.object.0[NS.object.1  """  ""?"3#$&-."*+5/06 8 668 66 6J86 > LMNOP FR6 &[Rectangle 3^_`abcdefghi n s ҁ(4&9\) 1!-xy Հ  [NS.object.0`0  !   VBorder "?"?P"?P"?P 86 6 "?""?""?  [NS.object.0[NS.object.1 "   "?"?"?"?  "?  "?""" ܀  #?#?xy    [NS.object.0`0  ! % & ' .! TFill * + , ."?"? y"? "? ķ 086 26 5 6 7 8"?""?""? : ; < >[NS.object.0[NS.object.1 @ A" D E F H"?"?"?"? J K"? N O P R"?""" U܀ #?#?#@ABC [ ] ^H a  4 ##@#@ f g h j"?"""@ABC l n o^ r$ #%: "##?#@ w x y {"?""" ~܀ '#?vwxy|~ > @   *+ E ,#@$#Z{0.5, 0.5} J ./0#?##?  2N 3#?#?@ABC   7 68TU 5###@ "?""?"?@ABC   < ;=T[ :###@ "?""?"?  Ɂ? ̀@  [NS.object.0A3#$<&-=>?"+5/06 86 6E8 H66J6MCB LMNOP88FR6 ^_`abcdefghi n s myk~\anRvfrDxy E  [NS.object.0F`0  !QOH! GIVBorder"?"?P"?P"?P 86 6"?"J"?""? [NS.object.0[NS.object.1KM"L!"?"?"?"?#$"?N'()+"?""".܀ P#?#?xy4S67 [NS.object.0T`0<=>BCD `]V.! _UWTFillGHIK"?"?X"?X"?XM86O6RSTU"?"X"?""?WXY [[NS.object.0[NS.object.1Y[]^"Zabce"?"?"?"?gh"?\klmo"?"""r܀ ^#?#?#@ABCxz{H~d ce4 b##@#@"?"""@ABC^i hj: g##?#@"?"""܀ l#?vwxy|~ > @ op E q#@$#Z{0.5, 0.5}J stu#?##?wN x#?#?@ABCǁ| {}TU z###@"?""?"?@ABCف T[ ###@"?""?"?UVXJ  [NS.object.0[NS.object.1[NS.object.2[NS.object.3mnopqrs6 v6 IIImnopqrs6v6V{0, 1}V{0, 1}V{0, 1}mnopqrs6v6   V{1, 1}V{1, 1}V{1, 1}mnopqrs6v6V{1, 0}V{1, 0}V{1, 0}$0 "%&' )[NS.object.0[NS.object.1+,."""013""?"3#$&-."*+5/066878668;66?6J86C0܁. LMNOPEFGR6J;UVPath 6^_`abcdefghiMNOPnRSTUsVWXƁҁā׀\ǁρˁxy[]^ [NS.object.0`0bcdhi ! VBorderlmnp"?"?P"?P"?Pr86t6wxyz"?""?""?|}~ [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#@xy [NS.object.0`0 . TFill"?"?X"?X"?X866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?#@ABCH 4 ##@#@"?"""@ABC^€ À: ##?#@"?"""܀ ŀ#?vwxy|~ > @ ȁɀ E #@$#Z{0.5, 0.5}J ́́#?##?"%ЀN #?#?@ABC)+,0Հ ԁրTU ###@5679"?""?"?@ABC;=>Bڀ فۀT[ ###@GHIK"?""?"?MO݁-SUV [NS.object.0߀3#$<&-=?"+5/06Z8J\6E^_66J6d ", LMNOP88fR6JTPath^_`abcdefghiklmnnpqrsstuv  \ xyy{| [NS.object.0`0 ! VBorder"?"?P"?P"?P866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?xy [NS.object.0`0ˀ .! TFill"?"?X"?X"?X866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?#@ABCH 4 ##@#@   "?"""@ABC^  : ##?#@"?""""܀  #?vwxy|~ > @ -.2 E #@$#Z{0.5, 0.5}9:;J #?##?@CN #?#?@ABCGIJN TU ###@STUW"?""?"?@ABCY[\` !T[ ###@efgi"?""?"?UVkX6# opq s[NS.object.0[NS.object.1$(mnopqrs6vv6yz{&%']{0, 0.465909}]{0, 0.465909}]{0, 0.465909}mnopqrsJvJ * )+_{0.978448, 0.477273}_{0.978448, 0.477273}_{0.978448, 0.477273}VW_MSShapePathLayer[_MSShapePathLayerWMSLayer0/ 1 [NS.object.0[NS.object.123"""""?"3#$&-."*+5/0686666J675u 6LMNOPRJ1 UGroup^_`abcdefghinsʁ_k]p\S`EhXd8xỳ9 [NS.object.0:`0ۀ DB; <"?"?P"?P"?P866"?"="?""? [NS.object.0[NS.object.1>@"?"?"?"?"?"?A"?"""܀ C#?#?xyF [NS.object.0G`0 ROH.! QI !"$"?"?X"?X"?X&86(6+,-."?"J"?""?012 4[NS.object.0[NS.object.1KM67"L:;<>"?"?"?"?@A"?NDEFH"?"""K܀ P#?#?#@ABCQSTHWV UW4 T##@#@\]^`"?"""@ABCbde^h[ Z\: Y##?#@mnoq"?"""t܀ ^#?vwxy|~ > @ ab E c#@$#Z{0.5, 0.5}J efg#?##?iN j#?#?@ABCn moTU l###@"?""?"?@ABCs rtT[ q###@"?""?"?vÀw [NS.object.0[NS.object.1x3#$&-."*+5/06668666J86{Zy zLMNOP88R6ZTriangle 5^_`abcdefghins\|xy} [NS.object.0~`0! VBorder"?"?P"?P"?P86 6  "?""?""? [NS.object.0[NS.object.1""?"?"?"?!""?%&')"?""",܀ #?#?xy245 [NS.object.0`0:;<@AB .! TFillEFGI"?"? y"? "? ķK86M6PQRS"?""?""?UVW Y[NS.object.0[NS.object.1[\"_`ac"?"?"?"?ef"?ijkm"?"""p܀ #?#?#@ABCvxyH| 4 ##@#@"?"""@ABC^ : ##?#@"?"""܀ #?vwxy|~ > @  E #@$#Z{0.5, 0.5}J #?##?N #?#?@ABCŁ TU ###@"?""?"?@ABCׁ T[ ###@"?""?"? [NS.object.03#$<&-=?"+5/06866E666J6d]isEquilateral LMNOP88R6^_`abcdefghin  s   \ށρxy [NS.object.0À`0!΁́ŀ! āVBorder!"#%"?"?P"?P"?P'86)6,-./"?""?""?123 5[NS.object.0[NS.object.1Ȁ78"ɀ;<=?"?"?"?"?AB"?ˀEFGI"?"""L܀ ̀#?#?xyRTU [NS.object.0р`0Z[\`ab ݁ځӀ.! ܁ҁTFillefgi"?"?X"?X"?Xk86m6pqrs"?""?""?uvw y[NS.object.0[NS.object.1ր{|"׀"?"?"?"?"?ـ"?"""܀ ۀ#?#?#@ABCH 4 ##@#@"?"""@ABC^ : ##?#@"?"""܀ #?vwxy|~ > @ Ɂ E #@$#Z{0.5, 0.5}ҀJ #?##?ځN #?#?@ABC TU ###@"?""?"?@ABC T[ ###@"?""?"?UVXJ    [NS.object.0[NS.object.1[NS.object.2 mnopqrs6v6X{0.5, 0}X{0.5, 0}X{0.5, 0}mnopqrs6v6 V{1, 1}V{1, 1}V{1, 1}mnopqrs6%v6()*   V{0, 1}V{0, 1}V{0, 1}VW/0_MSTriangleShape1234[_MSTriangleShape_MSCustomShapeLayer_MSShapePathLayerWMSLayer08 =@AB D[NS.object.0[NS.object.1FGI"""KLN""?"3#$&-."*+5/06Q8RS668V66Z6J86^Y LMNOP`JaR6d[Rectangle 7^_`abcdefghighijnlmnospqrCOAT\7D(L<Hxyuwx [NS.object.0`0|}~!'% VBorder"?"?P"?P"?P866"?" "?""? [NS.object.0[NS.object.1!#"""?"?"?"?"?$"?"""܀ &#?#?xy) [NS.object.0*`0ǀ 63,.! 5+-TFill"?"? y"? "? ķ866"?"."?""? [NS.object.0[NS.object.1/1"0"?"?"?"?"?2"?"""܀ 4#?#?#@ABCH: 9;4 8##@#@ "?"""@ABC ^? >@: =##?#@"?"""܀ B#?vwxy|~ > @ )*.EF E G#@$#Z{0.5, 0.5}567J IJK#?##?<?MN N#?#?@ABCCEFJR QSTU P###@OPQS"?""?"?@ABCUWX\W VXT[ U###@abce"?""?"?giZm[op [NS.object.0\3#$<&-=>?"+5/06t8Jv6E8xH66J6d^ ] LMNOP88R6d^_`abcdefghins\|m_xy` [NS.object.0a`0!ljc! bdVBorder"?"?P"?P"?P866"?"e"?""? [NS.object.0[NS.object.1fh"g"?"?"?"?"?i"?"""܀ k#?#?xyԀn [NS.object.0o`0 {xq.! zprTFill"?"?X"?X"?X866"?"s"?""? [NS.object.0[NS.object.1tv"u"?"?"?"?"?w   "?"""܀ y#?#?#@ABCH ~4 }##@#@#$%'"?"""@ABC)+,^/ : ##?#@4568"?""";܀ #?vwxy|~ > @ FGK E #@$#Z{0.5, 0.5}RSTJ #?##?Y\N #?#?@ABC`bcg TU ###@lmnp"?""?"?@ABCrtuy T[ ###@~"?""?"?UVXJ  [NS.object.0[NS.object.1[NS.object.2[NS.object.3mnopqrs6 v6 IIImnopqrs6v6V{0, 1}V{0, 1}V{0, 1}mnopqrs6v6V{1, 1}V{1, 1}V{1, 1}mnopqrs6v6V{1, 0}V{1, 0}V{1, 0}S0  [NS.object.0[NS.object.1"""""?"wVW\MSLayerGroup[\MSLayerGroupWMSLayer3#$&-."*+5/066666J6 LMNOPRJ21 ZGroup copy^_`abcdefghins\ׁȁ܁xy [NS.object.0`0  ǁŁ VBorder"?"?P"?P"?P866"?""?""? !" $[NS.object.0[NS.object.1&'"€*+,."?"?"?"?01"?Ā4568"?""";܀ ƀ#?#?xyACD [NS.object.0ʀ`0IJKOPQ ցӁ̀.! ՁˁTFillTUVX"?"?X"?X"?XZ86\6_`ab"?""?""?def h[NS.object.0[NS.object.1πjk"Ѐnopr"?"?"?"?tu"?Ҁxyz|"?"""܀ Ԁ#?#?#@ABCHڀ فۀ4 ##@#@"?"""@ABC^߀ ށ: ##?#@"?"""܀ #?vwxy|~ > @  E #@$#Z{0.5, 0.5}J #?##?ɁN #?#?@ABCԁ TU ###@"?""?"?@ABC T[ ###@"?""?"?7 [NS.object.0[NS.object.13#$&-."*+5/0666866 6J86Z? LMNOP88R6ZTriangle 5^_`abcdefghins !)5':\*2".xy$&' [NS.object.0`0+,-12!   VBorder5679"?"?P"?P"?P;86=6@ABC"?""?""?EFG I[NS.object.0[NS.object.1 KL"OPQS"?"?"?"?UV"? YZ[]"?"""`܀  #?#?xyfhi [NS.object.0`0noptuv .! TFillyz{}"?"? y"? "? ķ866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?#@ABCH !4 ##@#@"?"""@ABC^% $&: ###?#@"?"""܀ (#?vwxy|~ > @ ݁+, E -#@$#Z{0.5, 0.5}J /01#?##?3N 4#?#?@ABC8 79TU 6###@"?""?"?@ABC = <>T[ ;###@"?""?"?@A [NS.object.0B3#$<&-=?"+5/06#86%6E6(66J6MDC LMNOP880R63^_`abcdefghi5678n:;<=s>?@nzl\boSwgsExyCFEF [NS.object.0G`0JKLPQ!RPI! HJVBorderTUVX"?"?P"?P"?PZ86\6_`ab"?"K"?""?def h[NS.object.0[NS.object.1LNjk"Mnopr"?"?"?"?tu"?Oxyz|"?"""܀ Q#?#?xyT [NS.object.0U`0 a^W.! `VXTFill"?"?X"?X"?X866"?"Y"?""? [NS.object.0[NS.object.1Z\"["?"?"?"?"?]"?"""܀ _#?#?#@ABCHρe df4 c##@#@"?"""@ABC^j ik: h##?#@"?"""܀ m#?vwxy|~ > @ pq E r#@$#Z{0.5, 0.5}J tuv#?##?  xN y#?#?@ABC} |~TU {###@!"?""?"?@ABC#%&* T[ ###@/013"?""?"?UV5XJ 9:;< >?[NS.object.0[NS.object.1[NS.object.2mnopqrs6Bv6EFGX{0.5, 0}X{0.5, 0}X{0.5, 0}mnopqrs6Mv6PQRV{1, 1}V{1, 1}V{1, 1}mnopqrs6Xv6[\]V{0, 1}V{0, 1}V{0, 1}0d ilmn p[NS.object.0[NS.object.1rsu"""wxz""?"3#$&-."*+5/06}8~668666J863܁1 LMNOPJR6d[Rectangle 7^_`abcdefghinsƁҁā׀\ǁρˁxy [NS.object.0`0! VBorder"?"?P"?P"?P866"?""?""? S.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?xy [NS.object.0`0 .! TFill"?"? y"? "? ķ866"?""?""?  [NS.object.0[NS.object.1  ""?"?"?"?"?"?""" ܀ #?#?#@ABC&()H, 4 ##@#@1235"?"""@ABC79:^=€ À: ##?#@BCDF"?"""I܀ ŀ#?vwxy|~ > @ TUYȁɀ E #@$#Z{0.5, 0.5}`abJ ́́#?##?gjЀN #?#?@ABCnpquՀ ԁրTU ###@z{|~"?""?"?@ABCڀ فۀT[ ###@"?""?"?݁0 [NS.object.0߀3#$<&-=>?"+5/068J6E8H66J6M ! LMNOP88R6d^_`abcdefghins  \ xy [NS.object.0`0ˀ!! VBorder"?"?P"?P"?P866"?""?""? [NS.object.0[NS.object.1""?"?"?"?"?"?"""܀ #?#?xy [NS.object.0`0   .! TFill"?"?X"?X"?X866 "?""?""?"#$ &[NS.object.0[NS.object.1()",-.0"?"?"?"?23"?678:"?"""=܀ #?#?#@ABCCEFHI 4 ##@#@NOPR"?"""@ABCTVW^Z : ##?#@_`ac"?"""f܀  #?vwxy|~ > @ qrv  E #@$#Z{0.5, 0.5}}~J #?##?N #?#?@ABC TU ###@"?""?"?@ABC  T[ ###@"?""?"?UVXJ"  [NS.object.0[NS.object.1[NS.object.2[NS.object.3#$(,mnopqrs6 v6 IIImnopqrs6v6&%'V{0, 1}V{0, 1}V{0, 1}mnopqrs6v6*)+V{1, 1}V{1, 1}V{1, 1}mnopqrs6v6.-/V{1, 0}V{1, 0}V{1, 0}S02 4 [NS.object.0[NS.object.156"""""?"w&xy:   [NS.object.0[NS.object.1[NS.object.2;?B LMNOP08J66WoptionsZshouldTrim_includeRetinaVersion^includedLayers  @><=WSlice 1 VW WMSSlice!"[WMSSliceVMSRect LMNOP086%&'6*6,-@>@@AVserver  LMNOP086345686:;@>@CDVswitch xyAFCD  [NS.object.0[NS.object.1?BY{564, 59}JKLMNTbaseVguidesIJ VWRS[MSRulerDataT[[MSRulerDataJKVWNLJ \]s^_^thickGridTimesXgridSizeNVWab\MSSimpleGridcd[\MSSimpleGridZMSBaseGridVWfgVMSPagehij[VMSPage\MSLayerGroupWMSLayerlmnVstylesQR VWrs_MSTextStyleControllert[_MSTextStyleController vwTVyUVW{|_NSMutableDictionary{}[\NSDictionaryVW_MSLayerStylesController[_MSLayerStylesControllerXVW\NSMutableSet[UNSSet8\NSRangeCountZVW_NSMutableIndexSet[_NSMutableIndexSetZNSIndexSetVW^MSDocumentData[^MSDocumentDataZMSArchiverTroot"+5:?*6<OgvTjpy 09ABDFIKNSVWX[^_abdgjklm,:DV`lqw!*4:DMVXZ\^`bdfho&,7=ANTYZ_`bdins !6;@EGLUdks| #,:CQdpy &9;=?ACEGIKMOQVkpuz| $).05BGIK`ejoqv '/13579;=FOXmrw|~ %',5JShv .5LXqx !#%')+4=FOfm279;=?ACEGPYbw|  $-BGLQSXat(*-/46[gs  . @ T ^ t u w z | } ~ !!!!! ! ! !!!!!!'!3!5!7!\!^!`!b!d!f!h!j!l!n!u!!!!!!!!!!!!!!!!!"" """" "%"'")">"C"H"M"O"T"a"f"h"j"""""""""""""""""""# ##########!###(#=#B#G#L#N#S#|######################$$$$$$$$2$7$<$A$C$H$U$W$Y$[$d$m$v$$$$$$$$$$$$$$$$$%%%% % %%%%%$%-%B%G%L%Q%S%X%e%g%i%k%t%%%%%%%%%%%%%%%%%%%%%%%&& &&&&(&*&,&.&7&@&a&c&e&g&i&k&m&o&q&z&&&&&&&&&&&&&&&&&&&''''"''')'.';'='@'C'P'R'U'W'`'l'n'p'''''''''''''''''''(((((((Q(S(U(W(Y([(](_(a(c(e(g(i(r(t(v((((((((((((((((((((()!)&)'),)-)/)1)6);)@)M)Y)e)g)i)k)x)})))))))))))))))))))))** *****(*4*6*8*e*g*i*k*m*o*q*s*u*w*y*{*****************++ +++++++0+2+4+I+N+S+X+Z+_+l+q+s+u+++++++++++++++++++++,, ,,),.,3,8,:,?,\,^,`,b,d,f,h,j,s,|,,,,,,,,,,,,,,,,,,,- - -------(-3-H-J-L-N-P-R-[-d-m-~--------------------... ..0.2.4.6.8.:.<.>.@.I.R.[.p.u.z............../ //"/./1/4/6/8/://@/C/d/q/u///////////////////000000 0"0$0/0:0F0g0h0j0l0m0o0q0s000000000000001 1 1111111#1/1:1[1\1_1a1b1e1h1j1u111111111111122222 2 2222)262?2K2P2\2e2x222222223 3 33)303C3P3]3i3l3o3q3v3x333333333333334 44&41464;4>4C4L4e4j44444444444445555f5g5j5m5p5q5r5u5x5y5z5}5~55555555555555555555566666666)6,6.6S6U6X6[6^6`6b6d6g6j6q6666666666666666667 7 7777$7'7)7>7C7H7M7O7T7a7f7i7k77777777777777777778888888 8"8$8'8*8-828G8L8Q8V8X8]88888888888888888888899 9999"9'9*9,9A9F9K9P9R9W9d9f9i9k9t9}999999999999999999:::: :#:%:':*:3:<:E:Z:_:d:i:k:p:}:::::::::::::::::::::; ;;;;;;";+;4;E;H;J;L;O;X;a;;;;;;;;;;;;;;;;;;;<<<<< < <<<<#<,!>&>'>,>->/>2>7><>A>N>Z>f>i>k>n>{>>>>>>>>>>>>>>>>>>>>??????!?#?&?/?;?>?@?m?o?q?t?w?z?|?~????????????????????@@@@'@*@,@/@<@A@D@F@[@`@e@j@l@q@~@@@@@@@@@@@@@@@@@AAAA A AAAA#A,AAAFAKAPARAWAtAwAyA|AAAAAAAAAAAAAAAAAABBBBB B BB'B*B-B/B1B3B6B?BHBSBhBjBlBoBrBuB~BBBBBBBBBBBBBBBBBBBCC C"C'C,C1C3C8CYC\C^CaCdCfChCjCmCvCCCCCCCCCCCCCCCDD DDDDDD;DE@EAEDEGEIERE`EnEwEEEEEEEEEEEEEEEEEFF F FFF$F)F,F1FBFGFLFOFTFFFFFFFFFFFFFFFFFFFFFFFG&G)G,G/G2G4G7G:G=G@GCGFGIGRGTGWG`GlGoGqGGGGGGGGGGGGGGGGGHH HHHHHHH#H(H5HAHMHPHRHUHbHgHjHlHHHHHHHHHHHHHHHHHHHHHHII I II"I%I'ITIVIXI[I^IaIcIeIgIjImIpIuIIIIIIIIIIIIIIIIIJJJJJJ#J(J+J-JBJGJLJQJSJXJeJjJmJoJJJJJJJJJJJJJJJJJJJJJKK KK(K-K2K7K9K>K[K^K`KcKfKhKjKmKvKKKKKKKKKKKKKKKKKKKKLLLLLLLL&L/L:LOLQLSLVLYL\LeLnLwLLLLLLLLLLLLLLLLLLLM MMMMMM@MCMEMHMKMMMOMQMTM]MfMoMMMMMMMMMMMMMMMMMMNNN"N#N&N'N*N-N.N/N0N1N3NLNNNONQNNNNNNNNNNNNNNNNNNNNNNNNOOOOO O OO)O.O3O8O:O?OhOmOnOsOtOvOyO~OOOOOOOOOOOOOOOOOOPP P PP#P(P-P2P4P9PFPHPKPMPVP_PhPjPmPvPPPPPPPPPPPPPPPPPPPPPQQ)Q.Q/Q4Q5Q7Q:Q?QDQIQVQbQnQqQsQvQQQQQQQQQQQQQQQQQQQQRR R RRR R)RFRIRKRNRQRSRURXRaRjRsRRRRRRRRRRRRRRRRRRSSS SSS S"S%S'S0SISKSMSOSQSSSUSnSqStSvSxSzS}SSSSSSSSSSSSSSSSSSTT%T(T*T-T0T2T4T6T9TBTKTTTiTnTsTxTzTTTTTTTTTTTTTTTTTTTUU U UU#U/U;UGUSUVUXU[U^UaUUUUUUUUUUUUUUUUUUUUUUVVVVV V VVV"VCVDVGVIVJVMVPVRVYV`VgVlVyV|VVVVVVVVVVVVVVVVVVVVWWW WUWVWYW\W_W`WaWdWgWhWiWlWmWnWoWrWWWWWWWWWWWWWWWWWWWWXX X XX"X%X'XLXNXQXTXWXYX[X]X`XcXjXXXXXXXXXXXXXXXXXXYYYY YYY Y"Y7Y\S\X\]\b\d\i\v\x\{\}\\\\\\\\\\\\\\\\\\]]] ] ]]]]$]-]>]A]C]E]H]Q]Z]{]~]]]]]]]]]]]]]]]]]]]]^^^^^ ^^^%^:^?^D^I^K^P^]^`^c^f^s^u^x^{^^^^^^^^^^^^^^^^^_____<_?_B_E_H_J_M_P_S_V_Y_\___h_j_m_v____________________``#`$`)`*`,`/`4`9`>`K`W`c`f`h`k`x`}````````````````````aaa aaa a#a,a8a;a=ajalanaqatawaya{a}aaaaaaaaaaaaaaaaaaaab bb$b'b)b,b9b>bAbCbXb]bbbgbibnb{bbbbbbbbbbbbbbbbbbcccc c ccc c)c>cCcHcMcOcTcqctcvcyc|c~cccccccccccccccccddddd d d$d'd*d,d.d0d3df?fBfEfGfhfiflfnfofrfufwf~ffffffffffffffffffffgggggg(g+g.g0g5g7g@gCgFgSg_gkgngpgsgggggggggghhhh hhhhhhhhhhhh!h:hChEhGhHhJhVhhhhhhhhhhhhhhhhhhhhhhiiiii i iiii.i3i8i=i?iDimirisixiyi{i~iiiiiiiiiiiiiiiiiiij jjjj(j-j2j7j9j>jKjMjPjRj[jdjmjojrj{jjjjjjjjjjjjjjjjjjjjkkk.k3k4k9k:knGnPnYnnnsnxn}nnnnnnnnnnnnnnnnnnnno oooo"o$o'o*o3o?oBoDooooooooooooooooooooooooopppp ppppp%p1p4p6p[p]p`pcpfphpjplpoprpypppppppppppppppppqqqqqq'q,q/q1qFqKqPqUqWq\qiqnqqqsqqqqqqqqqqqqqqqqqqqrrrr r#r&r(r*r,r/r2r5r:rOrTrYr^r`rerrrrrrrrrrrrrrrrrrrrss sssss*s/s2s4sIsNsSsXsZs_slsnsqsss|sssssssssssssssssstt t#t%t(t+t-t/t2t;tDtMtbtgtltqtstxttttttttttttttttttttttuuuuuu!u*u3uyAyDyGyJyMyPySy\y^yayjyvyyy{yyyyyyyyyyyyyyyyyzzzzzz z#z(z-z2z?zKzWzZz\z_zlzqztzvzzzzzzzzzzzzzzzzzzzz{{ {{{{ {,{/{1{^{`{b{e{h{k{m{o{q{t{w{z{{{{{{{{{{{{{{{{{|| |||| |-|2|5|7|L|Q|V|[|]|b|o|t|w|y||||||||||||||||||||}} }}}2}7}<}A}C}H}e}h}j}m}p}r}t}w}}}}}}}}}}}}}}}}}}}}}~~~~ ~"~$~'~0~9~D~Y~[~]~`~c~f~o~x~~~~~~~~~~~~~~~~~~~~"$)JMORUWY[^gpy"#&'*+.123458QSUV[ʀրـہ 38=BDIrwx}~́сԁց-27<>CPRUW`irtw‚łȂ˂͂ςтԂׂڂ߂ 389>?ADINS`lx{}ƒσԃ׃ك!*3PSUX[]_bkt}ńȄʄ̈́Є҄Ԅׄ *,/1:SUWY[]_x{~Åƅυ؅/247:<>@CLU^sx}džІن%1=@BEfgjlmpsućƇLJʇ͇χ07JRUbehjoqz}ÈȈˈЈ(),/036789:;>WY[]_`bhɉˉΉ׉ !$9>CHJOx}~ŠŊҊ׊ڊ܊38=BDIVX[]foxz}ċƋȋˋ΋ыӋՋ׋ڋ݋ 49:?@BEJOTamy|~ÌЌՌ،ڌ"+4QTVY\^`clu~ƍɍˍ΍эӍՍ؍ +-02;TVXZ\^`y|ĎǎЎَ0358;=?ADMV_ty~ȏяڏ(*-0=IUXZ]ÐĐǐ'*-0358;>ADGJSUXamprʑϑԑّۑ $)6BNQSVchkmĒɒΒӒՒڒ #&(UWY\_bdfhknqvʓϓГՓ֓ؓۓ$),.CHMRTYfknpʔ ).38:?\_adgiknwÕƕȕѕ'0;PRTWZ]foxƖɖ˖ΖіӖՖזږ  ADFILNPRU^gp×Ɨϗۗޗ-.12567:=>?@AD]_abdŘǘʘӘߘ  'JVY[^a͟Οџӟԟןڟܟ!(/6?Q\nƠɠ̠٠ -27:?¡ġơǡɡբ !$'*-68;DPSUz|â %1469FKNPejotv{ʣ̣ϣѣڣ 8:EHUX[]bdmpsñԱٱޱPQTVYZ]`abcdeh̲ϲҲղزڲݲ<>ADGIKMPSZoty~ijɳγ۳ ',168=JORTinsxzȴ˴ʹ 05:?AFotuz{}ɵεѵӵ */49;@MORT]foζӶضݶ߶ %.CHMRTYfhkmv÷̷շ .1358AJknpsvxz|Ÿ */49;@MPSVcehkx "-behknpsvy|ҺԺ׺ںݺߺ DIJOPRUZ_dq}»ǻ̻λӻ "$')2;DFIR^acƼ˼мռ׼ܽ  %2>JMOR_dgi~ŽʽϽѽֽ"%'*-/14=FOdinsuzľپ޾ %')+-/1JMPRTVYbkvĿǿɿ˿ο׿ '0EJOTV[| Z[^_bcdgjklmnp 57:=@BDFILShmrwy~§¬­²³µ¸½ %*/16CHKMbglqsxÅÇÊÌÕÞçéìõ ).38:?hmnstvy~ăĈĕġĭİIJĵ #(-249FHKMV_hŅňŊōŐŒŔŗŠũŲ '?BDEHKMT[beruxzɁɊɍɐɝɩɵɸɺɽNORUXYZ]`abefghkʄʆʈʊʋʗ<>ADGIKMPSZoty~ˀ˅ˮ˳˴˹˺˼˿ ',168=JORTinsxž̜̥̮̰̳̼̎̑̓ 05:?AFotuz{}̀͊ͅ͏ͨ͜ʹͷ͹ͼ */49;@MORT]foΌΏΑΔΗΙΛΞΧΰι %.CHMRTYfhkmvϏϑϓϕϗϙϛϴϷϺϼϾ .1358AJknpsvxz|ЈБКЯдйо */49;@MPSVcehktрух,/258:=@CFILOXZ]fruwҜҞҡҤҧҩҫҭҰҳҺ$).;GSVX[hmprӇӌӑӖӘӝӪӯӲӴ(+-Z\^adgikmpsv{ԐԕԚԟԡԦ).13HMRWY^kpsuՊՏՔՙ՛ՠխկղմս.38=?Dadfilnps|օ֎ֲִֹ֣֭֨ #,5@UWY\_bkt}׎בדוטסת %FIKNQSUWZclu؊؏ؙؔ؛ؠحذسش(),./257XY\^_begnu|ٝٞ١٣٤٧٪٬ٳٺ #%.14AMY\^arw|ڄڕښڟڢڧڪڭڶڸڻ(0;Rabkmorsuvy|ۄۉۋ۔ۣۜ۫۲568:UU, AzY®`ee3z;:6Z& %"bvvv}™!N$A$?AX[[˲6 www `hydd.kj܇ g|> h[[`f(_h4nbS@3u&NNN 2@Dlg >ՆҷFH 8::}pHZ14MFsEeۍt:P(4pD.Y i#H㸹vfQW`CM0p~~I6Df2i($Ix@0p||r aŧ:Lj\>4t:Hۄahfs6h3i#LtY<z=C0 D"!2Dsi2 nnntfbrT*=uNh$:֗{<qF^fqqq7F9Mt:J%Ȳׯ_-IiDAFXtH0 Ԇ Ic/T*ɓ'MbuuuƦΗVٯ;N-u޽aL!Ԇϟ?y}vx~ *vuhq3 BA8dN+@|w>G&[[?۸dVAUUp?osfqPUZCϟ^T, Iw @ Xʹ}A05 e;ЂJ< *m(efywLEAE8#VĮR)~ư:,BXo߇A{(8y׼PTyxg_U,T8 9J^_àI]M]d_àI]aWf}-W0pF0lC ZV¡q-pF@zޜ-y&ǥo%i2't:![IWrV)Yv͛790MNOOQ()8nBzpp0ѡ!U,ny>ifu`pI1.'avQ,mҀ&(+unM@3!^_aqu}e8k& Ҽ˰HӶPeP(!NOOxȶ]F\Qq:] &x@$|8>.N&H_`&ɤd! q=vz6hEma)SA**], AzY® Fz=vVf QC 瑩j( T*PQ[>phˤP̑vj UU(T8[oJt߳z=5O>PPlA*-p(y:SvoڜIENDB`floodlight-0.90/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png0000664000175000017500000006151712041336206030201 0ustar jamespagejamespagePNG  IHDRg riCCPICC ProfileHTSiǿ^z";ҫzo6BB %PΠ##8T  AAY XP,8{vsvo}nAK:0BA Xd'˘CѸ;mr@(Grى(E R;Q{} e eq: ʧ8f8rkQ@a1?:#Hpy(lÎeqPމNb9FgO=#zX1K[M'2ϑx14)g%=ȼHoE/է8}93{OR8" R99-wCfrZң.E0ci`+Dp\C)On :Z| ˜2(nLl ݍQ: &070?g̝z70 :Ỗ4 X_8Y#tD;Ua.Xt q 2+`; lY`+y`/8JQPIp4*n !0 ^I0 f CTIA * B yBP@<(ʂCyPTj_U=q-F` ,jr=@x5'p6.p#|C+x #.b8">H8MH.R#H ҁG a] ac001%jL#s3|RXm% `csEJ9ul/v;8u m5Zq=k>x>??$ C !#l#j /3D*ђC3](q$JR'YIqbR=:iL&+-~d.y ||EkEoĜ8bbbFhMHcӶӎӮFqL8<]b$]Τ'}/ZkY{>HHIFIJ6HJ~bH9KKjz"֒^/}D􄌸 [&W#YXVK_vll씜_5 y||eqWPKÞ(f3&eS)v)(+)mSjPzLR6WV.TnSTQPRRSyJT5WU=ڡAM]-DmZژ:S=SN}PaQ@iyX[ 2ъ*պ kjsk`u,tx::]{4:a=6&U/߷c7} 52d>0m6j6zcme|xfeä䫩tL,¬̬\|M f,M-S,O[akoUk5B}EԊ+FYǬl66? *ڲlm)q*^kٟ p8qc,\E%ƥeukm[?Sf0'7{P<7пh300Gifo>yRTio5 ]v|{ɿ~N}^BE͘q+_⿚^k>oof~')ߩӉ3r?J}ds3l,%`[M8:UPu@Z-xy ^z>Lh OTݼ-?"9hA&ԚξC}#^3M_+aQ/:k)pA_,J IDATxzIOlrulf骲-Qdf2-VvqpprAᗐsF!4!3RJH){=RJ!`&{c9מB)5K7k-ofᏝsp5}l. ߧ o o9g`s5+gާ~{Կ>}[Nlo %P V?#.=o!g>7~׷?!h9XZ#Yc gZkW` { 1FNNi}6zO)qZ)Ol4=ڠڴOqR4Mq6{c p@k k-ssmFҁR M9A/ |:?<<7~ϵ=B\S}?mxV{nZC+קkRG?*7ˌ%=3/|iׁNQTg,6uthۖ?l6Nh=&<᪩7q1 |i_XzAo^Ղ8>c |gxcZM_2q<|d eO)!L|29(A@S:Q='`Zw / \tRSG6:?eImc ׬Nǵ:^+1eç45ʦr q_:CrJ#沆VW{9ԁ1Qkdz$0x$MSdIW=o8flV)ocվ*1f9V(5ourkYr褁9>Y/ $|LZgblALy*C + ((7wciݐ/  o:u]цnt0JQ)ڎ7sk,LcSkO}GQfcՉ:cRƬXRFbL4Ɓ7zʖP@@J))v8mߣ:Xkqssj#}CAJeSz&<<<`ɔ~x:"7nkuD:Ym 0S/ Qʊ)-1fXZ cY@7E}<ڥ>9~Ǧ7Znͬt7s[b?e8>_uwREɆkcL)Ĉh"P~~wu$N89#b(S/ct'5vHG'K _+Yg˩6T^D{@(qxZ3mZfQS@\cz | GƮK=.(XIMpImg# k$hH4VKyo.+㌢}M!AA!g&]s R(04M,œ mJ@丗-zz>9)wFN~ܓ\.9O9' sڮEsk3@mԅq@C &OK~wo#A.:%O7m!;oFRcTSc+; "$}* `UL]mۢ{t GA.IW_jUy}[}?uS.B M@yL6j@Q-@c\eOVF$9cϗ/_p8B=O 8YmfhuߗMUJk KfҶ9ܪYm?.٘)@Z  g(8_9X XCyi]Gʉdp9`>;Ͼ !bR\ğu;'eep,0" $,'p{dӺ 1mW2Y(fB*b9܀JK`=JDeÁEC@36}zk$TC6֠ Q+%PQz.#6ȶhFz|n?#]i9ÁY=n4E(=/Ւ22rȈxpJ;`~LV57x=[ ܬ<pvb^+p8XT9S=ڦ]Rv/N>AK\|Lm$SNƕҁ '^IWխ~RåX;ieӿd*}By~Rr7k+`*#)(&MǕ5@Q%u?m_|=o>}㵛_۶2ٹo/@RGed6qB.~M`-wP6J)GpϟaEZc p=$Љ?;}wwwlKm$ڎ{-6}iFOxOAhl٣~iYlR1)%{$ԖÁ[_ -MԣS? OZg9ub@ZLaObD$}ϯvw @@6ZO m j ̲W>/=ZidyV[duWyG(xl48^&@A^Z4aG|i'7o4ul7O)ƭ\dEBMܖ)9WF牃4J4&!ၳJ޽ÇXa A8 )%{|y?uYnwM1 i';abL&q`]&!Xa z@A^ JFi:=gKzVOfc(.C14=ɜE:ު_ 4܅%ad)8lj벦+{5} 9};rX[36F>MPDjڶH «R>}bOgx9O5 -q6\'QZ$`n!2=|ҧSsh|I «@ijc^|id+M[,}sJsmV~g`0 V[JIrfe41F#:IT_]_,nk0[ms,b7Yo~M_#l;OFh)} j j]o Ax1(Zv;vթKR~v-uoeaZ3 ~*<ml2~PYumy]֦X8;4MJ @A^ [ pww+ſM[[Ʃ8ď1v{v;h|@㬠l ޤ."ĒGBy=R[*y9R۸ 0 +5jͲƢitMcL7w\$yUeFF SF8`G;?~! iE۴1FٗQ)cR iUž>! OGi{<ϖV?m.Oi~ St¤:0ch~4Z2KYT?o6 @+z _j   Gn~8?~/buIyw}9MkXV/va͹H9Cb!aPC75NNLc`r)=!'T:UChL>MӔ <m/* R{a[ה֕VH1#vyyxx@ʉS)% G !,ƕ~,.v 8^=ꀮozN<KETaZ!/|)~7f=81YS.)}&?qm(՟J ozl-M~1D@Va[q A)=)%˗/l; 12G+85gPz? )&-C y hس=8.w8V6Ik逩j\5='sn%᧠?-www?Vdb)nh7_A@inǧq1N#OocTB })g=Bl+.I  ?M}yd/ RT=XG?bU;%8+ր4JCcV#IBϟsnٹ4$oC"6Z)6O4?6Ӽ#SJ Y7 )A |y6X zJ3{ll^?c5ާk56h\ߣk;haOaF.sX>~r. ھ6wwdE]v;8=ڶe])l{8M)ombo>" 3ƥaC:eLN;mJ x$0p9? Ax6S( J"UJg1VEwe[[Z }hS-{ OeL,W#谴ـ3Ag PA@I_ǦR Z K2Q>k^x`a*ޏ1 oUVP6M٠ZXz" ς4j1TJ9Ʊي5}KzY `^{o6ה~x:Eis>Pߗ/_WJh}Zg[ׇ=vaϩ 9e'%3F۶n1r>+:)KIu~~*_h걞 <6A: ߶- r}qs&js֡k2]G5%"2/#s?b3C \S0=K ^EigZ"0mTX2Ls ;c%sm5#a;Q {( @I YZkRÁs4@'|\p@=u??*qPyC[]~qd# |ʘ)Osjh9@ͻ;^Ш0ȧ~\Y>ҷ/u|<ذg|9ey @%. RB۴t4o>~Mp;6;(' e CF扖hS+ HsnA믿gxV.Smғ5eKΎ<&u=6φa8ǓuBB:ӢFNieEcܖ}Sғ=n/:JTk QWO h "rmZxmbj}֥Mj^#ߝt>`nScĈ)LH!qF _"_ ^? >6Ӥʦ8P{sm86/_G@:UTݳ.6JYD N+iJ -`T>wQ(GJM?x KpXڒcIӠN6/֕!WmrPP8·LTXY6X׵]9c_@+o Κi呡Ix)!W]օ|W}XWr*ͦk#歵l6KqIAXc9O_{;OAxcZmCJ#b+_ZϡOt8.Y\ TJd>K( >,m)eMNO j-]=d{$x @}QAUkTs!spΩ-x^ij2ƜEيEc ڕa Al2lv)6R3V uи~5J q%"PĀ"Á ~+olEP}e@iwꅡF%:04n\ ߃~>( [d(@5z )'aw{qoEE~!Ān7៫ݗ;G'}OZmە V k]_mrhb0Ts JG8OjrڎGRotu_2jċd`!bb{}v*$ƈnS!xA%W=9k&FXD)\2nqc_NG1;t`#b (%55in}9Wt] ~^C7dvK1=E\ST9Y F=v0#ϩV0(>S9fDSJk8NoVY_ 3F% ̵SR5d<>#5Fi1xߤr)/Oӄq9%,ֿ:~dXX$WkldSdԔrʥ<ʁ!*YkSH{*ʟ#9WAIR"y1kڦyZ qruyfnC %4Ǖ M%3~0Ơmۓv%39/S )+42|>y%fY HFs{"֢*H@8#Jnju@\3 @ƣS8J WLЦOu[MUP@J F-}Ru]ӎuR7a!/ɋL0H1a'x㡲BT1JN ^RR;JV ‹Qw) 2jVQmk7:mcDi0ŸjPC:R]TxҒpԭGOl4kb [h`Ay 8 Ţv |ޟ.g)uVE^DARh#{jW0mv֡kbL]wAjR @"@#ODAb((SE P>律l4xK=e0ZW.V@Bk  \)$ ybk-t*QpL*rl/,Auՠk ᪩ǏJsmqPFF!b4#v 5 0 ҊUTJkAx1 S^IP6.(MR죏0ʰ7ӼQJA㱦24H2 8R Yxxldk\)D^HqeqDWk_•rk )-gbr ڔǏ1F4m0 0M屖Mbc ‹kS%(`)?84MSҼ9!YR.7:wA(TF^9Wo@)ZNDP1 ZA  AxUִcTlJXsF6dr$·<}QJĄQA^j|j("T c B)4Ms[) -T{Z|!$+{#U0(`s]^1uHORH |bX^)4 "  \! " \1Q-:o R7.ފPZl)5 er$Io <*eV\тpBS/<+y [D2p| \)AS Vru( \)߬do+7^M@ٴbȾhA|M))lѷ=ڮ-2 6#gXJqt=Z:[pP@uGc4 ti[aMa6Jm0 u"&@ml: "3bB IcAk  \9_-rK:4 6I0 -`ue9q+( rI?\Z{Bpij9#XcBR |Dg!>n 6PZi8t^E`Kk::ӛhAxfs)G£"B @VO0nS bP^aGyƖv 6Mis 5CLι\S! İꖠ`9 @"41E]蛶AM햃g;t%cV:Px#}hAx94 b,ɵJD3]s˃Mq9Cոm[ƕx۶0j fSr`x p7B8V@Abh%_}8|MH_W._mDF4M9@*GA29Ng_2#M^4  s^ِ:VDuDD~:pTTT쥿ଃ6~7M8(UFz`2e+)%#s#0c9髢Z+fͶR4*An&|=y/n|j*K" \1uV 'sΈ!(3t^=H;TW8vs5siflfd BfZ)p}?>2 PWz8S0C eQuHg!L$mg8qt80P)&a dmiqΖ9vi#n&%hFAZt]۴Q8.VsGI){?3؟u@tK&?no&k4G۵ZXƾhQf~*ޘyoۖ=E9MAySj9f6=;R4N >}Koe Q͹BשR {0Yk,mT/Beяe0c8Lk?q-s9ḾGS.Yi~vU`Lf&B朑fX~SLO^D}o7}LR$7% 14.&R\ы]b602>ҥ jh~5@倫?E5e_hE?FҪ,@M<ǟυJeW6q8B [b'm^~n Q1 ̝ z[o67l7up?)OÞH[Awж-.?Pk.υ m[*AT"ZVX (]L2¹rQk>a;Jg)s.8dAmu pL֏I%X{o_͋CO)`dR$-H%2 \¹So$tυPT9g nY 6slD Xnߤ@˂6y@᪇TMa TZ' 92Pk{qbF h5Vۯ 0V4:KŗAAx>OYn]#V&joT@W'΁@ (X6qWyjfJE?֟~NWXRCtksۙ>O֚[3)LUpbNw.K"z)uڎRDNE*gp첆0*Z<(%6My}cЦ]ߕpńp1 z}i==k^ K:}Q>1IB *HV) ȫ%3lXNP::%-PPR*u] f=W]J)kz50 |eVBnZAE6٥YBg=Ѹ:6mFCimA5A?umϧ%0 RNƖ5MA:(ĀaJ=eå]ɅT̴PÁXkS9UA h<0mMS6|K06-O֢Z8NnEyb4)P9m=M%Ԃ@>ߔ9apEmӲJ "B ƱLiuB ;PO]a&>x5iB^{da+QZqmvOR%Xd(1|}ߚ; snkl2ZU/]SJ6@%$'OBUSD=o'LӴ:%0::@>Iq\ߧX:j 'k}`SFtmfж%@~69ҵ)隮=k? ?ulonn(gEK \9戮'Jnp]u'_h,pΙOEt} MeJ2 H8*ц.k-6݆7ؓ(c[Ow=9o9`78c߯,?/w_Vi\5Rr&H5[}BNGvz~rq]m4fWi~8)'LTL \m’1NjA~^cVs%o#iXY~%™vmJ]2YMٌLۣ9#= DT8>+(Za)ЂkmB)fs?(tJ:_Z\'=ֺt eҙ%zo_N%OvֺMNٛ(:3WFȑ.InP0pNpx}&7-Sʏu` *`Z h>|KrU#< AH/DA<a'e8_*' 8?4|z]Ҽ c 6777Eg,M5j嫅s.z0q8pǑeP:?V=t}ۺ-m[VNӄ8΁ |e+'[5S}u-B)&KjU/%D4QнbYQfsk-ڦZca\uluߣg=[ҁhj֩>Yj!-H(y "}*v^׽s Zk@K&#*AxL}FOY6?7߷8.T&hFRLTW34$ŧ-{]qPu{e5䉙cƅz9^Xkk/ߧ>53l+uj3v0`0꡷7ʜ f u-F]!c+R̨D>zݳa5G^n1)6N{_C$mg)٦5=]z<1?#qXZo-{fo! ςjT92`0 FC8 L~.#G5\/$M ޽{Wֵ%kT R/~ԯMzeN8lD0컮11@gSQ3eBl"s) C)/ /ɔ9-{qlF-z^bdbZ'?j/sFA~ 5 sW Yp0^i .dkR -%Ckl1AӞ_FYӨB ^o %{x=+!! @!X:FœEJ+.iqss[p\kΆ?yVև]3 ZJ/-KsNIM=۔%A`FJFg]OMہ,{YrklFw|ǣy_G!?2/DT,&C}KQ&$᧨UiNzZ)UT嬝džVNu%S|[n:,o! ?E=@k>Xax*M4h#Q=. kߵviߣS }w¤4MH!!ºymJVQV7x=-w{1SE*٧{߱`&ߒ?Ol68~g-$Rh_DJXL~*?Vt6xZnfÞd>ca\isXFu§x?}^BՄ??@8o! 6㔪k]S.)، tʢl$#zmmس5u_C)?X'i_R֠7~BA^ 9Jc}K[ڞ^~8o! /m"OIDAc &?!bjk@Z_ z쭶.sڦkydc,qE]q! BCB1ZYey4Me0,PPF6_ ] w?ka)y.(ʱ?3_Yc}IwEA^ ޽{xsbʼn-<_k eED/ 5M_ﺎFw&?_' **55MwǏ@'Svf0 @'3îEte=]5~iKܶI|w~sw42{?}C{{^5,!@,Ҕb1B[OKt9NfoE}he(OY&?rX5)+c$$(unoo4 q)l+R6)&@o:S?ǔ >8b?yvۥձ"@WNS90 !v;i~w,+BB4w=f)&aPzn8Z<{߿砀zz  'Ak1PSzN- CS̄kd.c]ǣ1N#H(ЉݮLH  GRmb([!6iB?ydW6zfa~s[Xt"eo#Nzm\DAN h _9-]h{] )-cqKz?E &SJifvN?~dW~ A^z%4)%L~|`_}&$,ж-q NhJ) M\r:%l ^q?Op(@L9%3_*EJk8w%$젍r@&JР 0VJ`zRo lcGe/hpkڶe %q1cqv7 >߿/3o9H YVov8 B@'@k  l+m -`P?=c|i_'tV@  FJ ޽cap8V[a`lY3.RU׀𪤐)Ź?&1i, PwPG}־mW)|A8cꅟE˗/ib[G0PJAX(tB$-Z\TN>4M9G(ٜyjmrÇ?H@J tDAb.ucm45dTq3| #ͷOA0 \矦 p|VSlݻEѶ AHj aԅFSĂDFA!(V YRJ&O=6u F>8X漞@y麎P \>|s4!ƈAc8l1q: - c_Mu`ϩ)?ROl~FO9|0?l6< A8jQ7 ׌|)b{|gXL~Ӿk8 ,@N9nL9q?ۻu siIB-K+ $>3B8gjֱvȠxm^X,▐HN#%y6~ْRd_ ъBm}/yeN _HƖ/`K1zyNzЦkW=۠o݊nfߞ>$m*R}>xdڶ4!iMui',M4$Az]kۮ<ڠooԤM\j\K8x(Lț˯ v :m@+ q%/?ζ3\M! @Bg)mҸ&mv{|oة}i_D%߿ǩ}Be>$ 0*f]v4Ag|ʼ›. 3koV6;boKם1Y2:t?c`"oE}H< pz>5]t\5.H鶫QӧnЎ߾v]kyuůc{_{,JǪb&z3$+!lͲ,ӭj%]=~n0^A+] h~ˮrmטg!n𻝘Xhfܞ[KZힿgvů_G\VU,_WiF-=2e"`Zb0{yyט HlU ?A^Jb :6&_@D۱y.>DYD$aw1߇a~jA;ۏY}W$ߴ͛RDž|{~,KyzzC[4.b!3J֩ Xv%M~8艄 Al?x(HB#x*_~gw{x}l?&E:t'~=}QẮc%7+im4PڒNdz7j \73dXdIVdOóguK@}%c?{z{|>]' 68`lß^,AiX_B{ Q ,v0:ܯmoCzL/Ǧyl6ed{~2 A]ZDfpzqIuRELD$&`*o)C_)T꺎AXf,c5PrC 9v< $y~Ouq⠲sm?WL#xYOWG=ΰBl^[., }fB-m]ꮷN%@oGO0i _u UUŲ>'z N q~97crmV %؄ LtZp([~l6xۜ+|{ݮgTD) \8Jt]g hE`^kзw6kןV RV*ޮ36:~l6ؿH]@z7AZ^<3a@z} vŝ4Ho1 o/2@h3~, D( u]Qv՟n;؏"=TO??=hgc:-ݧ~0zu}j@V0ҏ |M$ #D0B$ #D0B$ #D0B$ #D0B$PyZBW{,eYvy$44M#[,lpםeTU%yKee0O89'_~Iu~9v?KFQ$4|.y~xpVAz-/GD>|}6/^"eYJ۶eEqJ$ 9qD._# cdYvtHKuwUx9S $lYU֫G1NǏ"rI EB⽿SxaP%TuphO g0B$sg2UU~0I㪪($YEQr?J۶1u?3',˘ey p&!jJG-~-Be)yKQ$9p@zOAߧA_;Hُ߁Q.­7P_~P'|{JH#dܷ\b 0o `H!F"`H!F ƤE`/OIENDB`floodlight-0.90/src/main/images/README0000664000175000017500000000013112041336206020101 0ustar jamespagejamespageThese icons were created with Sketch, available at http://www.bohemiancoding.com/sketch/ floodlight-0.90/src/test/0000775000175000017500000000000012041336206016014 5ustar jamespagejamespagefloodlight-0.90/src/test/java/0000775000175000017500000000000012041336206016735 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/0000775000175000017500000000000012041336206017523 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/0000775000175000017500000000000012041336206023762 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/0000775000175000017500000000000012041336206026554 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/internal/0000775000175000017500000000000012041336206030370 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootfloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.javafloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.0000664000175000017500000001420112041336206034605 0ustar jamespagejamespage/** * Copyright 2012 Big Switch Networks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Iterator; import org.junit.Test; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import junit.framework.TestCase; /** * * @author gregor * */ public class DeviceUniqueIndexTest extends TestCase { protected Entity e1a; protected Entity e1b; protected Device d1; protected Entity e2; protected Entity e2alt; protected Entity e3; protected Entity e4; @Override protected void setUp() throws Exception { super.setUp(); e1a = new Entity(1L, (short)1, 1, 1L, 1, new Date()); e1b = new Entity(1L, (short)2, 1, 1L, 1, new Date()); List d1Entities = new ArrayList(2); d1Entities.add(e1a); d1Entities.add(e1b); d1 = new Device(null, Long.valueOf(1), null, null, d1Entities, null); // e2 and e2 alt match in MAC and VLAN e2 = new Entity(2L, (short)2, 2, 2L, 2, new Date()); e2alt = new Entity(2, (short)2, null, null, null, null); // IP is null e3 = new Entity(3L, (short)3, null, 3L, 3, new Date()); // IP and switch and port are null e4 = new Entity(4L, (short)4, null, null, null, new Date()); } /* * Checks that the iterator it returns the elements in the Set expected * Doesn't check how often an element is returned as long it's at least * once */ protected void verifyIterator(Set expected, Iterator it) { HashSet actual = new HashSet(); while (it.hasNext()) { actual.add(it.next()); } assertEquals(expected, actual); } @Test public void testDeviceUniqueIndex() { DeviceUniqueIndex idx1 = new DeviceUniqueIndex( EnumSet.of(DeviceField.MAC, DeviceField.VLAN)); idx1.updateIndex(d1, d1.getDeviceKey()); idx1.updateIndex(e2, 2L); //------------- // Test findByEntity lookups assertEquals(Long.valueOf(1L), idx1.findByEntity(e1a)); assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); assertEquals(Long.valueOf(2L), idx1.findByEntity(e2)); // we didn't add e2alt but since they key fields are the same we // should find it assertEquals(Long.valueOf(2L), idx1.findByEntity(e2alt)); assertEquals(null, idx1.findByEntity(e3)); assertEquals(null, idx1.findByEntity(e4)); //------------- // Test getAll() HashSet expectedKeys = new HashSet(); expectedKeys.add(1L); expectedKeys.add(2L); verifyIterator(expectedKeys, idx1.getAll()); //------------- // Test queryByEntity() verifyIterator(Collections.singleton(1L), idx1.queryByEntity(e1a)); verifyIterator(Collections.singleton(1L), idx1.queryByEntity(e1b)); verifyIterator(Collections.singleton(2L), idx1.queryByEntity(e2)); verifyIterator(Collections.singleton(2L), idx1.queryByEntity(e2alt)); assertEquals(false, idx1.queryByEntity(e3).hasNext()); assertEquals(false, idx1.queryByEntity(e3).hasNext()); //------------- // Test removal idx1.removeEntity(e1a, 42L); // No-op. e1a isn't mapped to this key assertEquals(Long.valueOf(1L), idx1.findByEntity(e1a)); idx1.removeEntity(e1a, 1L); assertEquals(null, idx1.findByEntity(e1a)); assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); assertEquals(Long.valueOf(2L), idx1.findByEntity(e2)); idx1.removeEntity(e2); assertEquals(null, idx1.findByEntity(e2)); assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); //------------- // Test null keys DeviceUniqueIndex idx2 = new DeviceUniqueIndex( EnumSet.of(DeviceField.IPV4, DeviceField.SWITCH)); // only one key field is null idx2.updateIndex(e3, 3L); assertEquals(Long.valueOf(3L), idx2.findByEntity(e3)); e3.ipv4Address = 3; assertEquals(null, idx2.findByEntity(e3)); // all key fields are null idx2.updateIndex(e4, 4L); assertEquals(null, idx2.findByEntity(e4)); Device d4 = new Device(null, 4L, null, null, Collections.singleton(e4), null); idx2.updateIndex(d4, 4L); assertEquals(null, idx2.findByEntity(e4)); //------------- // entity already exists with different deviceKey DeviceUniqueIndex idx3 = new DeviceUniqueIndex( EnumSet.of(DeviceField.MAC, DeviceField.VLAN)); idx3.updateIndex(e1a, 42L); assertEquals(false, idx3.updateIndex(d1, 1L)); // TODO: shouldn't this fail as well so that the behavior // is consistent? idx3.updateIndex(e1a, 1L); // anyways. We can now add d1 ;-) assertEquals(true, idx3.updateIndex(d1, 1L)); } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootfloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.javafloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.0000664000175000017500000023372212041336206034556 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.internal; import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static org.easymock.EasyMock.expectLastCall; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.devicemanager.IDeviceListener; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus; import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.ClassState; import net.floodlightcontroller.devicemanager.test.MockEntityClassifier; import net.floodlightcontroller.devicemanager.test.MockEntityClassifierMac; import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier; import net.floodlightcontroller.flowcache.FlowReconcileManager; import net.floodlightcontroller.flowcache.IFlowReconcileService; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.ITopologyService; import static org.junit.Assert.*; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFType; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.util.HexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DeviceManagerImplTest extends FloodlightTestCase { protected static Logger logger = LoggerFactory.getLogger(DeviceManagerImplTest.class); protected OFPacketIn packetIn_1, packetIn_2, packetIn_3; protected IPacket testARPReplyPacket_1, testARPReplyPacket_2, testARPReplyPacket_3; protected IPacket testARPReqPacket_1, testARPReqPacket_2; protected byte[] testARPReplyPacket_1_Srld, testARPReplyPacket_2_Srld; private byte[] testARPReplyPacket_3_Serialized; MockFloodlightProvider mockFloodlightProvider; DeviceManagerImpl deviceManager; MemoryStorageSource storageSource; FlowReconcileManager flowReconcileMgr; private IOFSwitch makeSwitchMock(long id) { IOFSwitch mockSwitch = createMock(IOFSwitch.class); expect(mockSwitch.getId()).andReturn(id).anyTimes(); expect(mockSwitch.getStringId()). andReturn(HexString.toHexString(id, 6)).anyTimes(); expect(mockSwitch.getPort(anyShort())). andReturn(new OFPhysicalPort()).anyTimes(); expect(mockSwitch.portEnabled(isA(OFPhysicalPort.class))). andReturn(true).anyTimes(); return mockSwitch; } @Before public void setUp() throws Exception { super.setUp(); FloodlightModuleContext fmc = new FloodlightModuleContext(); RestApiServer restApi = new RestApiServer(); MockThreadPoolService tp = new MockThreadPoolService(); ITopologyService topology = createMock(ITopologyService.class); fmc.addService(IThreadPoolService.class, tp); mockFloodlightProvider = getMockFloodlightProvider(); deviceManager = new DeviceManagerImpl(); flowReconcileMgr = new FlowReconcileManager(); DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); fmc.addService(IDeviceService.class, deviceManager); storageSource = new MemoryStorageSource(); fmc.addService(IStorageSourceService.class, storageSource); fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); fmc.addService(IRestApiService.class, restApi); fmc.addService(IFlowReconcileService.class, flowReconcileMgr); fmc.addService(IEntityClassifierService.class, entityClassifier); fmc.addService(ITopologyService.class, topology); tp.init(fmc); restApi.init(fmc); storageSource.init(fmc); deviceManager.init(fmc); flowReconcileMgr.init(fmc); entityClassifier.init(fmc); storageSource.startUp(fmc); deviceManager.startUp(fmc); flowReconcileMgr.startUp(fmc); tp.startUp(fmc); entityClassifier.startUp(fmc); reset(topology); topology.addListener(deviceManager); expectLastCall().anyTimes(); replay(topology); IOFSwitch mockSwitch1 = makeSwitchMock(1L); IOFSwitch mockSwitch10 = makeSwitchMock(10L); IOFSwitch mockSwitch5 = makeSwitchMock(5L); IOFSwitch mockSwitch50 = makeSwitchMock(50L); Map switches = new HashMap(); switches.put(1L, mockSwitch1); switches.put(10L, mockSwitch10); switches.put(5L, mockSwitch5); switches.put(50L, mockSwitch50); mockFloodlightProvider.setSwitches(switches); replay(mockSwitch1, mockSwitch5, mockSwitch10, mockSwitch50); // Build our test packet this.testARPReplyPacket_1 = new Ethernet() .setSourceMACAddress("00:44:33:22:11:01") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setVlanID((short)5) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); this.testARPReplyPacket_1_Srld = testARPReplyPacket_1.serialize(); // Another test packet with a different source IP this.testARPReplyPacket_2 = new Ethernet() .setSourceMACAddress("00:44:33:22:11:01") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); this.testARPReplyPacket_2_Srld = testARPReplyPacket_2.serialize(); this.testARPReplyPacket_3 = new Ethernet() .setSourceMACAddress("00:44:33:22:11:01") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.3")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); this.testARPReplyPacket_3_Serialized = testARPReplyPacket_3.serialize(); // Build the PacketIn this.packetIn_1 = ((OFPacketIn) mockFloodlightProvider. getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testARPReplyPacket_1_Srld) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) this.testARPReplyPacket_1_Srld.length); // Build the PacketIn this.packetIn_2 = ((OFPacketIn) mockFloodlightProvider. getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testARPReplyPacket_2_Srld) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) this.testARPReplyPacket_2_Srld.length); // Build the PacketIn this.packetIn_3 = ((OFPacketIn) mockFloodlightProvider. getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testARPReplyPacket_3_Serialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) this.testARPReplyPacket_3_Serialized.length); } @Test public void testLastSeen() throws Exception { Calendar c = Calendar.getInstance(); Date d1 = c.getTime(); Entity entity1 = new Entity(1L, null, null, null, null, d1); c.add(Calendar.SECOND, 1); Entity entity2 = new Entity(1L, null, 1, null, null, c.getTime()); IDevice d = deviceManager.learnDeviceByEntity(entity2); assertEquals(c.getTime(), d.getLastSeen()); d = deviceManager.learnDeviceByEntity(entity1); assertEquals(c.getTime(), d.getLastSeen()); deviceManager.startUp(null); d = deviceManager.learnDeviceByEntity(entity1); assertEquals(d1, d.getLastSeen()); d = deviceManager.learnDeviceByEntity(entity2); assertEquals(c.getTime(), d.getLastSeen()); } @Test public void testEntityLearning() throws Exception { IDeviceListener mockListener = createStrictMock(IDeviceListener.class); deviceManager.addListener(mockListener); deviceManager.entityClassifier= new MockEntityClassifier(); deviceManager.startUp(null); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isConsistent(10L, (short)1, 10L, (short)1)). andReturn(true).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)). andReturn(true).anyTimes(); expect(mockTopology.isConsistent(50L, (short)3, 50L, (short)3)). andReturn(true).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); deviceManager.topology = mockTopology; Entity entity1 = new Entity(1L, null, null, 1L, 1, new Date()); Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date()); Entity entity3 = new Entity(1L, null, 1, 10L, 1, new Date()); Entity entity4 = new Entity(1L, null, 1, 1L, 1, new Date()); Entity entity5 = new Entity(2L, (short)4, 1, 5L, 2, new Date()); Entity entity6 = new Entity(2L, (short)4, 1, 50L, 3, new Date()); Entity entity7 = new Entity(2L, (short)4, 2, 50L, 3, new Date()); mockListener.deviceAdded(isA(IDevice.class)); replay(mockListener, mockTopology); Device d1 = deviceManager.learnDeviceByEntity(entity1); assertSame(d1, deviceManager.learnDeviceByEntity(entity1)); assertSame(d1, deviceManager.findDeviceByEntity(entity1)); assertEquals(DefaultEntityClassifier.entityClass , d1.entityClass); assertArrayEquals(new Short[] { -1 }, d1.getVlanId()); assertArrayEquals(new Integer[] { }, d1.getIPv4Addresses()); assertEquals(1, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); mockListener.deviceAdded(isA(IDevice.class)); replay(mockListener); Device d2 = deviceManager.learnDeviceByEntity(entity2); assertFalse(d1.equals(d2)); assertNotSame(d1, d2); assertNotSame(d1.getDeviceKey(), d2.getDeviceKey()); assertEquals(MockEntityClassifier.testEC, d2.entityClass); assertArrayEquals(new Short[] { -1 }, d2.getVlanId()); assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses()); assertEquals(2, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); replay(mockListener); Device d3 = deviceManager.learnDeviceByEntity(entity3); assertNotSame(d2, d3); assertEquals(d2.getDeviceKey(), d3.getDeviceKey()); assertEquals(MockEntityClassifier.testEC, d3.entityClass); assertArrayEquals(new Integer[] { 1 }, d3.getIPv4Addresses()); assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, d3.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, d3.getAttachmentPoints(true)); assertArrayEquals(new Short[] { -1 }, d3.getVlanId()); assertEquals(2, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); replay(mockListener); Device d4 = deviceManager.learnDeviceByEntity(entity4); assertNotSame(d1, d4); assertEquals(d1.getDeviceKey(), d4.getDeviceKey()); assertEquals(DefaultEntityClassifier.entityClass, d4.entityClass); assertArrayEquals(new Integer[] { 1 }, d4.getIPv4Addresses()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, d4.getAttachmentPoints()); assertArrayEquals(new Short[] { -1 }, d4.getVlanId()); assertEquals(2, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); mockListener.deviceAdded((isA(IDevice.class))); replay(mockListener); Device d5 = deviceManager.learnDeviceByEntity(entity5); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 2) }, d5.getAttachmentPoints()); assertArrayEquals(new Short[] { (short) 4 }, d5.getVlanId()); assertEquals(2L, d5.getMACAddress()); assertEquals("00:00:00:00:00:02", d5.getMACAddressString()); verify(mockListener); reset(mockListener); mockListener.deviceAdded(isA(IDevice.class)); replay(mockListener); Device d6 = deviceManager.learnDeviceByEntity(entity6); assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) }, d6.getAttachmentPoints()); assertArrayEquals(new Short[] { (short) 4 }, d6.getVlanId()); assertEquals(4, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); replay(mockListener); Device d7 = deviceManager.learnDeviceByEntity(entity7); assertNotSame(d6, d7); assertEquals(d6.getDeviceKey(), d7.getDeviceKey()); assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) }, d7.getAttachmentPoints()); assertArrayEquals(new Short[] { (short) 4 }, d7.getVlanId()); assertEquals(4, deviceManager.getAllDevices().size()); verify(mockListener); reset(mockListener); replay(mockListener); reset(deviceManager.topology); deviceManager.topology.addListener(deviceManager); expectLastCall().times(1); replay(deviceManager.topology); deviceManager.entityClassifier = new MockEntityClassifierMac(); deviceManager.startUp(null); Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date()); assertEquals(null, deviceManager.learnDeviceByEntity(entityNoClass)); verify(mockListener); } @Test public void testAttachmentPointLearning() throws Exception { IDeviceListener mockListener = createStrictMock(IDeviceListener.class); deviceManager.addListener(mockListener); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.getL2DomainId(1L)). andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)). andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(10L)). andReturn(10L).anyTimes(); expect(mockTopology.getL2DomainId(50L)). andReturn(10L).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(10L, (short)1, 50L, (short)1)). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); Entity entity0 = new Entity(1L, null, null, null, null, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime()); IDevice d; SwitchPort[] aps; Integer[] ips; mockListener.deviceAdded(isA(IDevice.class)); replay(mockListener); deviceManager.learnDeviceByEntity(entity1); d = deviceManager.learnDeviceByEntity(entity0); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity2); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity3); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] {new SwitchPort(5L, 1), new SwitchPort(10L, 1)}, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity4); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1), new SwitchPort(50L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); } @Test public void testAttachmentPointSuppression() throws Exception { IDeviceListener mockListener = createStrictMock(IDeviceListener.class); deviceManager.addListener(mockListener); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.getL2DomainId(1L)). andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)). andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(10L)). andReturn(10L).anyTimes(); expect(mockTopology.getL2DomainId(50L)). andReturn(10L).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isConsistent(5L, (short)1, 50L, (short)1)). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; // suppress (1L, 1) and (10L, 1) deviceManager.addSuppressAPs(1L, (short)1); deviceManager.addSuppressAPs(10L, (short)1); Calendar c = Calendar.getInstance(); Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); Entity entity0 = new Entity(1L, null, null, null, null, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); c.add(Calendar.SECOND, 1); Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime()); IDevice d; SwitchPort[] aps; Integer[] ips; mockListener.deviceAdded(isA(IDevice.class)); replay(mockListener); deviceManager.learnDeviceByEntity(entity1); d = deviceManager.learnDeviceByEntity(entity0); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertEquals(aps.length, 0); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity2); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity3); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); //verify(mockListener); // There is no device movement here; no not needed. reset(mockListener); mockListener.deviceMoved((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity4); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1), new SwitchPort(50L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); } @Test public void testBDAttachmentPointLearning() throws Exception { ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(1L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isBroadcastDomainPort(1L, (short)2)). andReturn(true).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, 1L, (short)2)).andReturn(true).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(1L, (short)2, 1L, (short)1)).andReturn(true).anyTimes(); expect(mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); c.add(Calendar.MILLISECOND, (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2); Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime()); c.add(Calendar.MILLISECOND, (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT / 2 + 1); Entity entity3 = new Entity(1L, null, null, 1L, 2, c.getTime()); IDevice d; SwitchPort[] aps; d = deviceManager.learnDeviceByEntity(entity1); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); // this timestamp is too soon; don't switch d = deviceManager.learnDeviceByEntity(entity2); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); // it should switch when we learn with a timestamp after the // timeout d = deviceManager.learnDeviceByEntity(entity3); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2) }, aps); } @Test public void testPacketIn() throws Exception { byte[] dataLayerSource = ((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress(); // Mock up our expected behavior ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())). andReturn(true).anyTimes(); expect(mockTopology.isConsistent(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())).andReturn(false). anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); Date currentDate = new Date(); // build our expected Device Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); Device device = new Device(deviceManager, new Long(deviceManager.deviceKeyCounter), new Entity(Ethernet.toLong(dataLayerSource), (short)5, ipaddr, 1L, 1, currentDate), DefaultEntityClassifier.entityClass); // Get the listener and trigger the packet in IOFSwitch switch1 = mockFloodlightProvider.getSwitches().get(1L); mockFloodlightProvider.dispatchMessage(switch1, this.packetIn_1); // Verify the replay matched our expectations // verify(mockTopology); // Verify the device Device rdevice = (Device) deviceManager.findDevice(Ethernet.toLong(dataLayerSource), (short)5, null, null, null); assertEquals(device, rdevice); assertEquals(new Short((short)5), rdevice.getVlanId()[0]); Device result = null; Iterator dstiter = deviceManager.queryClassDevices(device, null, null, ipaddr, null, null); if (dstiter.hasNext()) { result = (Device)dstiter.next(); } assertEquals(device, result); device = new Device(device, new Entity(Ethernet.toLong(dataLayerSource), (short)5, ipaddr, 5L, 2, currentDate)); reset(mockTopology); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true). anyTimes(); expect(mockTopology.isConsistent(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())).andReturn(false). anyTimes(); expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(false) .anyTimes(); expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, 5L, (short)2)). andReturn(false).anyTimes(); // Start recording the replay on the mocks replay(mockTopology); // Get the listener and trigger the packet in IOFSwitch switch5 = mockFloodlightProvider.getSwitches().get(5L); mockFloodlightProvider. dispatchMessage(switch5, this.packetIn_1.setInPort((short)2)); // Verify the replay matched our expectations verify(mockTopology); // Verify the device rdevice = (Device) deviceManager.findDevice(Ethernet.toLong(dataLayerSource), (short)5, null, null, null); assertEquals(device, rdevice); } /** * Note: Entity expiration does not result in device moved notification. * @throws Exception */ public void doTestEntityExpiration() throws Exception { IDeviceListener mockListener = createStrictMock(IDeviceListener.class); mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(1L, (short)1)).andReturn(false).anyTimes(); expect(mockTopology.isBroadcastDomainPort(5L, (short)1)).andReturn(false).anyTimes(); expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)).andReturn(5L).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); Entity entity1 = new Entity(1L, null, 2, 1L, 1, c.getTime()); c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); Entity entity2 = new Entity(1L, null, 1, 5L, 1, c.getTime()); deviceManager.learnDeviceByEntity(entity1); IDevice d = deviceManager.learnDeviceByEntity(entity2); assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1)}, d.getAttachmentPoints()); Iterator diter = deviceManager.queryClassDevices(d, null, null, 1, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); diter = deviceManager.queryClassDevices(d, null, null, 2, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); deviceManager.addListener(mockListener); replay(mockListener); deviceManager.entityCleanupTask.reschedule(0, null); d = deviceManager.getDevice(d.getDeviceKey()); assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses()); // Attachment points are not removed, previous ones are still valid. assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1) }, d.getAttachmentPoints()); diter = deviceManager.queryClassDevices(d, null, null, 2, null, null); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); diter = deviceManager.queryClassDevices(d, null, null, 1, null, null); assertFalse(diter.hasNext()); d = deviceManager.findDevice(1L, null, null, null, null); assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses()); // Attachment points are not removed, previous ones are still valid. assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1) }, d.getAttachmentPoints()); verify(mockListener); } public void doTestDeviceExpiration() throws Exception { IDeviceListener mockListener = createStrictMock(IDeviceListener.class); mockListener.deviceRemoved(isA(IDevice.class)); Calendar c = Calendar.getInstance(); c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); Entity entity2 = new Entity(1L, null, 2, 5L, 1, c.getTime()); ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())). andReturn(true). anyTimes(); expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes(); expect(mockTopology.isConsistent(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())).andReturn(false). anyTimes(); expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), EasyMock.anyShort())). andReturn(false).anyTimes(); replay(mockTopology); IDevice d = deviceManager.learnDeviceByEntity(entity2); d = deviceManager.learnDeviceByEntity(entity1); assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses()); deviceManager.addListener(mockListener); replay(mockListener); deviceManager.entityCleanupTask.reschedule(0, null); IDevice r = deviceManager.getDevice(d.getDeviceKey()); assertNull(r); Iterator diter = deviceManager.queryClassDevices(d, null, null, 1, null, null); assertFalse(diter.hasNext()); r = deviceManager.findDevice(1L, null, null, null, null); assertNull(r); verify(mockListener); } /* * A ConcurrentHashMap for devices (deviceMap) that can be used to test * code that specially handles concurrent modification situations. In * particular, we overwrite values() and will replace / remove all the * elements returned by values. * * The remove flag in the constructor specifies if devices returned by * values() should be removed or replaced. */ protected static class ConcurrentlyModifiedDeviceMap extends ConcurrentHashMap { private static final long serialVersionUID = 7784938535441180562L; protected boolean remove; public ConcurrentlyModifiedDeviceMap(boolean remove) { super(); this.remove = remove; } @Override public Collection values() { // Get the values from the real map and copy them since // the collection returned by values can reflect changed Collection devs = new ArrayList(super.values()); for (Device d: devs) { if (remove) { // We remove the device from the underlying map super.remove(d.getDeviceKey()); } else { super.remove(d.getDeviceKey()); // We add a different Device instance with the same // key to the map. We'll do some hackery so the device // is different enough to compare differently in equals // but otherwise looks the same. // It's ugly but it works. Entity[] curEntities = new Entity[d.getEntities().length]; int i = 0; // clone entities for (Entity e: d.getEntities()) { curEntities[i] = new Entity (e.macAddress, e.vlan, e.ipv4Address, e.switchDPID, e.switchPort, e.lastSeenTimestamp); if (e.vlan == null) curEntities[i].vlan = (short)1; else curEntities[i].vlan = (short)((e.vlan + 1 % 4095)+1); i++; } Device newDevice = new Device(d, curEntities[0]); newDevice.entities = curEntities; assertEquals(false, newDevice.equals(d)); super.put(newDevice.getDeviceKey(), newDevice); } } return devs; } } @Test public void testEntityExpiration() throws Exception { doTestEntityExpiration(); } @Test public void testDeviceExpiration() throws Exception { doTestDeviceExpiration(); } /* Test correct entity cleanup behavior when a concurrent modification * occurs. */ @Test public void testEntityExpirationConcurrentModification() throws Exception { deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false); doTestEntityExpiration(); } /* Test correct entity cleanup behavior when a concurrent remove * occurs. */ @Test public void testDeviceExpirationConcurrentRemove() throws Exception { deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(true); doTestDeviceExpiration(); } /* Test correct entity cleanup behavior when a concurrent modification * occurs. */ @Test public void testDeviceExpirationConcurrentModification() throws Exception { deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false); doTestDeviceExpiration(); } @Test public void testAttachmentPointFlapping() throws Exception { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)). andReturn(true).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 10L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(10L, (short)1, 1L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(5L, (short)1, 1L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(10L, (short)1, 5L, (short)1)). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime()); Entity entity1a = new Entity(1L, null, 1, 1L, 1, c.getTime()); Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); entity1.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); entity1a.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity2.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity3.setLastSeenTimestamp(c.getTime()); IDevice d; d = deviceManager.learnDeviceByEntity(entity1); d = deviceManager.learnDeviceByEntity(entity1a); d = deviceManager.learnDeviceByEntity(entity2); d = deviceManager.learnDeviceByEntity(entity3); // all entities are active, so entity3 should win assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1),}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); // all are still active; entity3 should still win assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1, ErrorStatus.DUPLICATE_DEVICE), new SwitchPort(10L, 1, ErrorStatus.DUPLICATE_DEVICE) }, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+2000); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); assertEquals(entity1.getActiveSince(), entity1.getLastSeenTimestamp()); // entity1 should now be the only active entity assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, d.getAttachmentPoints(true)); } @Test public void testAttachmentPointFlappingTwoCluster() throws Exception { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); expect(mockTopology.getL2DomainId(1L)). andReturn(1L).anyTimes(); expect(mockTopology.getL2DomainId(5L)). andReturn(5L).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)2)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(1L, (short)2, 5L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(5L, (short)1, 5L, (short)2)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(1L, (short)2, 1L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)2)). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(5L, (short)2, 5L, (short)1)). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime()); Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime()); Entity entity3 = new Entity(1L, null, null, 5L, 1, c.getTime()); Entity entity4 = new Entity(1L, null, null, 5L, 2, c.getTime()); entity1.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); c.add(Calendar.MILLISECOND, 1); entity2.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity3.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity4.setLastSeenTimestamp(c.getTime()); deviceManager.learnDeviceByEntity(entity1); deviceManager.learnDeviceByEntity(entity2); deviceManager.learnDeviceByEntity(entity3); IDevice d = deviceManager.learnDeviceByEntity(entity4); // all entities are active, so entities 2,4 should win assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2), new SwitchPort(5L, 2) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2), new SwitchPort(5L, 2)}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, 1); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); // all entities are active, so entities 2,4 should win assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 2) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 2), new SwitchPort(1L, 2, ErrorStatus.DUPLICATE_DEVICE)}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); // entities 3,4 are still in conflict, but 1 should be resolved assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 2) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 2)}, d.getAttachmentPoints(true)); entity3.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity3); // no conflicts, 1 and 3 will win assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), new SwitchPort(5L, 1) }, d.getAttachmentPoints(true)); } protected void doTestDeviceQuery() throws Exception { Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date()); Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date()); Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date()); deviceManager.learnDeviceByEntity(entity1); deviceManager.learnDeviceByEntity(entity2); deviceManager.learnDeviceByEntity(entity3); deviceManager.learnDeviceByEntity(entity4); Iterator iter = deviceManager.queryDevices(null, (short)1, 1, null, null); int count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(1, count); iter = deviceManager.queryDevices(null, (short)3, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(1, count); iter = deviceManager.queryDevices(null, (short)1, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(0, count); deviceManager.learnDeviceByEntity(entity5); iter = deviceManager.queryDevices(null, (short)4, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(2, count); } @Test public void testDeviceIndex() throws Exception { EnumSet indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class); indexFields.add(IDeviceService.DeviceField.IPV4); indexFields.add(IDeviceService.DeviceField.VLAN); deviceManager.addIndex(false, indexFields); ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceQuery(); } @Test public void testDeviceQuery() throws Exception { ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceQuery(); } protected void doTestDeviceClassQuery() throws Exception { Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date()); Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date()); Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date()); IDevice d = deviceManager.learnDeviceByEntity(entity1); deviceManager.learnDeviceByEntity(entity2); deviceManager.learnDeviceByEntity(entity3); deviceManager.learnDeviceByEntity(entity4); Iterator iter = deviceManager.queryClassDevices(d, null, (short)1, 1, null, null); int count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(1, count); iter = deviceManager.queryClassDevices(d, null, (short)3, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(1, count); iter = deviceManager.queryClassDevices(d, null, (short)1, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(0, count); deviceManager.learnDeviceByEntity(entity5); iter = deviceManager.queryClassDevices(d, null, (short)4, 3, null, null); count = 0; while (iter.hasNext()) { count += 1; iter.next(); } assertEquals(2, count); } @Test public void testDeviceClassIndex() throws Exception { EnumSet indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class); indexFields.add(IDeviceService.DeviceField.IPV4); indexFields.add(IDeviceService.DeviceField.VLAN); deviceManager.addIndex(true, indexFields); ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceClassQuery(); } @Test public void testDeviceClassQuery() throws Exception { ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceClassQuery(); } @Test public void testFindDevice() { boolean exceptionCaught; deviceManager.entityClassifier= new MockEntityClassifierMac(); deviceManager.startUp(null); ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); Entity entity2b = new Entity(22L, (short)2, 2, 1L, 2, new Date()); Entity entity3 = new Entity(3L, (short)1, 3, 2L, 1, new Date()); Entity entity4 = new Entity(4L, (short)2, 4, 2L, 2, new Date()); Entity entity5 = new Entity(5L, (short)1, 5, 3L, 1, new Date()); IDevice d1 = deviceManager.learnDeviceByEntity(entity1); IDevice d2 = deviceManager.learnDeviceByEntity(entity2); IDevice d3 = deviceManager.learnDeviceByEntity(entity3); IDevice d4 = deviceManager.learnDeviceByEntity(entity4); IDevice d5 = deviceManager.learnDeviceByEntity(entity5); // Make sure the entity classifier worked as expected assertEquals(MockEntityClassifierMac.testECMac1, d1.getEntityClass()); assertEquals(MockEntityClassifierMac.testECMac1, d2.getEntityClass()); assertEquals(MockEntityClassifierMac.testECMac2, d3.getEntityClass()); assertEquals(MockEntityClassifierMac.testECMac2, d4.getEntityClass()); assertEquals(DefaultEntityClassifier.entityClass, d5.getEntityClass()); // Look up the device using findDevice() which uses only the primary // index assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), entity1.getVlan(), entity1.getIpv4Address(), entity1.getSwitchDPID(), entity1.getSwitchPort())); // port changed. Device will be found through class index assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), entity1.getVlan(), entity1.getIpv4Address(), entity1.getSwitchDPID(), entity1.getSwitchPort()+1)); // VLAN changed. No device matches assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), (short)42, entity1.getIpv4Address(), entity1.getSwitchDPID(), entity1.getSwitchPort())); assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), null, entity1.getIpv4Address(), entity1.getSwitchDPID(), entity1.getSwitchPort())); assertEquals(d2, deviceManager.findDeviceByEntity(entity2)); assertEquals(null, deviceManager.findDeviceByEntity(entity2b)); assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(), entity3.getVlan(), entity3.getIpv4Address(), entity3.getSwitchDPID(), entity3.getSwitchPort())); // switch and port not set. throws exception exceptionCaught = false; try { assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(), entity3.getVlan(), entity3.getIpv4Address(), null, null)); } catch (IllegalArgumentException e) { exceptionCaught = true; } if (!exceptionCaught) fail("findDevice() did not throw IllegalArgumentException"); assertEquals(d4, deviceManager.findDeviceByEntity(entity4)); assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), entity5.getVlan(), entity5.getIpv4Address(), entity5.getSwitchDPID(), entity5.getSwitchPort())); // switch and port not set. throws exception (swith/port are key // fields of IEntityClassifier but not d5.entityClass exceptionCaught = false; try { assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), entity5.getVlan(), entity5.getIpv4Address(), null, null)); } catch (IllegalArgumentException e) { exceptionCaught = true; } if (!exceptionCaught) fail("findDevice() did not throw IllegalArgumentException"); Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date()); assertEquals(null, deviceManager.findDeviceByEntity(entityNoClass)); // Now look up destination devices assertEquals(d1, deviceManager.findDestDevice(d2, entity1.getMacAddress(), entity1.getVlan(), entity1.getIpv4Address())); assertEquals(d1, deviceManager.findDestDevice(d2, entity1.getMacAddress(), entity1.getVlan(), null)); assertEquals(null, deviceManager.findDestDevice(d2, entity1.getMacAddress(), (short) -1, 0)); } @Test public void testGetIPv4Addresses() { // Looks like Date is only 1s granularity ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes(); expect(mockTopology.isConsistent(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(false) .anyTimes(); expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(false) .anyTimes(); expect(mockTopology.isInSameBroadcastDomain(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())). andReturn(false).anyTimes(); replay(mockTopology); Entity e1 = new Entity(1L, (short)1, null, null, null, new Date(2000)); Device d1 = deviceManager.learnDeviceByEntity(e1); assertArrayEquals(new Integer[0], d1.getIPv4Addresses()); Entity e2 = new Entity(2L, (short)2, 2, null, null, new Date(2000)); Device d2 = deviceManager.learnDeviceByEntity(e2); d2 = deviceManager.learnDeviceByEntity(e2); assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); // More than one entity Entity e2b = new Entity(2L, (short)2, null, 2L, 2, new Date(3000)); d2 = deviceManager.learnDeviceByEntity(e2b); assertEquals(2, d2.entities.length); assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); // and now add an entity with an IP Entity e2c = new Entity(2L, (short)2, 2, 2L, 3, new Date(3000)); d2 = deviceManager.learnDeviceByEntity(e2c); assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); assertEquals(3, d2.entities.length); // Other devices with different IPs shouldn't interfere Entity e3 = new Entity(3L, (short)3, 3, null, null, new Date(4000)); Entity e3b = new Entity(3L, (short)3, 3, 3L, 3, new Date(4400)); Device d3 = deviceManager.learnDeviceByEntity(e3); d3 = deviceManager.learnDeviceByEntity(e3b); assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); assertArrayEquals(new Integer[] { 3 }, d3.getIPv4Addresses()); // Add another IP to d3 Entity e3c = new Entity(3L, (short)3, 33, 3L, 3, new Date(4400)); d3 = deviceManager.learnDeviceByEntity(e3c); Integer[] ips = d3.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new Integer[] { 3, 33 }, ips); // Add another device that also claims IP2 but is older than e2 Entity e4 = new Entity(4L, (short)4, 2, null, null, new Date(1000)); Entity e4b = new Entity(4L, (short)4, null, 4L, 4, new Date(1000)); Device d4 = deviceManager.learnDeviceByEntity(e4); assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); // add another entity to d4 d4 = deviceManager.learnDeviceByEntity(e4b); assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); // Make e4 and e4a newer Entity e4c = new Entity(4L, (short)4, 2, null, null, new Date(5000)); Entity e4d = new Entity(4L, (short)4, null, 4L, 5, new Date(5000)); d4 = deviceManager.learnDeviceByEntity(e4c); d4 = deviceManager.learnDeviceByEntity(e4d); assertArrayEquals(new Integer[0], d2.getIPv4Addresses()); // FIXME: d4 should not return IP4 assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); // Add another newer entity to d2 but with different IP Entity e2d = new Entity(2L, (short)2, 22, 4L, 6, new Date(6000)); d2 = deviceManager.learnDeviceByEntity(e2d); assertArrayEquals(new Integer[] { 22 }, d2.getIPv4Addresses()); assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); // new IP for d2,d4 but with same timestamp. Both devices get the IP Entity e2e = new Entity(2L, (short)2, 42, 2L, 4, new Date(7000)); d2 = deviceManager.learnDeviceByEntity(e2e); ips= d2.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new Integer[] { 22, 42 }, ips); Entity e4e = new Entity(4L, (short)4, 42, 4L, 7, new Date(7000)); d4 = deviceManager.learnDeviceByEntity(e4e); ips= d4.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new Integer[] { 2, 42 }, ips); // add a couple more IPs Entity e2f = new Entity(2L, (short)2, 4242, 2L, 5, new Date(8000)); d2 = deviceManager.learnDeviceByEntity(e2f); ips= d2.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new Integer[] { 22, 42, 4242 }, ips); Entity e4f = new Entity(4L, (short)4, 4242, 4L, 8, new Date(9000)); d4 = deviceManager.learnDeviceByEntity(e4f); ips= d4.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new Integer[] { 2, 42, 4242 }, ips); } // TODO: this test should really go into a separate class that collects // unit tests for Device @Test public void testGetSwitchPortVlanId() { Entity entity1 = new Entity(1L, (short)1, null, 10L, 1, new Date()); Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date()); Entity entity3 = new Entity(1L, (short)3, null, 1L, 1, new Date()); Entity entity4 = new Entity(1L, (short)42, null, 1L, 1, new Date()); Entity[] entities = new Entity[] { entity1, entity2, entity3, entity4 }; Device d = new Device(null,1L, null, null, Arrays.asList(entities), null); SwitchPort swp1x1 = new SwitchPort(1L, 1); SwitchPort swp1x2 = new SwitchPort(1L, 2); SwitchPort swp2x1 = new SwitchPort(2L, 1); SwitchPort swp10x1 = new SwitchPort(10L, 1); assertArrayEquals(new Short[] { -1, 1}, d.getSwitchPortVlanIds(swp10x1)); assertArrayEquals(new Short[] { 3, 42}, d.getSwitchPortVlanIds(swp1x1)); assertArrayEquals(new Short[0], d.getSwitchPortVlanIds(swp1x2)); assertArrayEquals(new Short[0], d.getSwitchPortVlanIds(swp2x1)); } @Test public void testReclassifyDevice() { MockFlexEntityClassifier flexClassifier = new MockFlexEntityClassifier(); deviceManager.entityClassifier= flexClassifier; deviceManager.startUp(null); ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes(); expect(mockTopology.isConsistent(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(false) .anyTimes(); expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(false) .anyTimes(); replay(mockTopology); //flexClassifier.createTestEntityClass("Class1"); Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); Entity entity1b = new Entity(1L, (short)2, 1, 1L, 1, new Date()); Entity entity2 = new Entity(2L, (short)1, 2, 2L, 2, new Date()); Entity entity2b = new Entity(2L, (short)2, 2, 2L, 2, new Date()); Device d1 = deviceManager.learnDeviceByEntity(entity1); Device d2 = deviceManager.learnDeviceByEntity(entity2); Device d1b = deviceManager.learnDeviceByEntity(entity1b); Device d2b = deviceManager.learnDeviceByEntity(entity2b); d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(), entity1.getVlan(), entity1.getIpv4Address(), entity1.getSwitchDPID(), entity1.getSwitchPort()) .next(); d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(), entity1b.getVlan(), entity1b.getIpv4Address(), entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next(); assertEquals(d1, d1b); d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(), entity2.getVlan(), entity2.getIpv4Address(), entity2.getSwitchDPID(), entity2.getSwitchPort()).next(); d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(), entity2b.getVlan(), entity2b.getIpv4Address(), entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next(); assertEquals(d2, d2b); IEntityClass eC1 = flexClassifier.createTestEntityClass("C1"); IEntityClass eC2 = flexClassifier.createTestEntityClass("C2"); flexClassifier.addVlanEntities((short)1, eC1); flexClassifier.addVlanEntities((short)2, eC1); deviceManager.reclassifyDevice(d1); deviceManager.reclassifyDevice(d2); d1 = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity1)); d1b = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity1b)); assertEquals(d1, d1b); d2 = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity2)); d2b = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity2b)); assertEquals(d2, d2b); flexClassifier.addVlanEntities((short)1, eC2); deviceManager.reclassifyDevice(d1); deviceManager.reclassifyDevice(d2); d1 = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity1)); d1b = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity1b)); d2 = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity2)); d2b = deviceManager.deviceMap.get( deviceManager.primaryIndex.findByEntity(entity2b)); assertNotSame(d1, d1b); assertNotSame(d2, d2b); flexClassifier.addVlanEntities((short)1, eC1); deviceManager.reclassifyDevice(d1); deviceManager.reclassifyDevice(d2); ClassState classState = deviceManager.classStateMap.get(eC1.getName()); Long deviceKey1 = null; Long deviceKey1b = null; Long deviceKey2 = null; Long deviceKey2b = null; deviceKey1 = classState.classIndex.findByEntity(entity1); deviceKey1b = classState.classIndex.findByEntity(entity1b); deviceKey2 = classState.classIndex.findByEntity(entity2); deviceKey2b = classState.classIndex.findByEntity(entity2b); assertEquals(deviceKey1, deviceKey1b); assertEquals(deviceKey2, deviceKey2b); } } floodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/0000775000175000017500000000000012041336206027533 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.javafloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.j0000664000175000017500000000530512041336206034623 0ustar jamespagejamespage/** * */ package net.floodlightcontroller.devicemanager.test; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.internal.Entity; /** * Extension to simple entity classifier to help in unit tests to provide table * based multiple entity classification mock for reclassification tests * */ public class MockFlexEntityClassifier extends DefaultEntityClassifier { Map switchEntities; Map vlanEntities; public static class TestEntityClass implements IEntityClass { String name; public TestEntityClass(String name) { this.name = name; } @Override public EnumSet getKeyFields() { return EnumSet.of(MAC); } @Override public String getName() { return name; } } public static IEntityClass defaultClass = new TestEntityClass("default"); public MockFlexEntityClassifier() { switchEntities = new HashMap (); vlanEntities = new HashMap (); } public IEntityClass createTestEntityClass(String name) { return new TestEntityClass(name); } public void addSwitchEntity(Long dpid, IEntityClass entityClass) { switchEntities.put(dpid, entityClass); } public void removeSwitchEntity(Long dpid) { switchEntities.remove(dpid); } public void addVlanEntities(Short vlan, IEntityClass entityClass) { vlanEntities.put(vlan, entityClass); } public void removeVlanEntities(Short vlan) { vlanEntities.remove(vlan); } @Override public IEntityClass classifyEntity(Entity entity) { if (switchEntities.containsKey(entity.getSwitchDPID())) return switchEntities.get(entity.getSwitchDPID()); if (vlanEntities.containsKey(entity.getVlan())) return vlanEntities.get(entity.getVlan()); return defaultClass; } @Override public EnumSet getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootfloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.javafloodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.ja0000664000175000017500000000411612041336206034565 0ustar jamespagejamespagepackage net.floodlightcontroller.devicemanager.test; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; import java.util.EnumSet; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.internal.Entity; /** A simple IEntityClassifier. Useful for tests that need an IEntityClassifier * with switch/port as key fields. */ public class MockEntityClassifierMac extends DefaultEntityClassifier { public static class TestEntityClassMac implements IEntityClass { protected String name; public TestEntityClassMac(String name) { this.name = name; } @Override public EnumSet getKeyFields() { return EnumSet.of(MAC, VLAN); } @Override public String getName() { return name; } } public static IEntityClass testECMac1 = new MockEntityClassifierMac.TestEntityClassMac("testECMac1"); public static IEntityClass testECMac2 = new MockEntityClassifierMac.TestEntityClassMac("testECMac2"); @Override public IEntityClass classifyEntity(Entity entity) { if (entity.getSwitchDPID() == 1L) { return testECMac1; } else if (entity.getSwitchDPID() == 2L) { return testECMac2; } else if (entity.getSwitchDPID() == -1L) { return null; } return DefaultEntityClassifier.entityClass; } @Override public EnumSet getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } }floodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java0000664000175000017500000001007312041336206033703 0ustar jamespagejamespagepackage net.floodlightcontroller.devicemanager.test; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceListener; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.devicemanager.internal.AttachmentPoint; import net.floodlightcontroller.devicemanager.internal.Device; import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl; import net.floodlightcontroller.devicemanager.internal.Entity; /** * Mock device manager useful for unit tests * @author readams */ public class MockDeviceManager extends DeviceManagerImpl { /** * Set a new IEntityClassifier * Use this as a quick way to use a particular entity classifier in a * single test without having to setup the full FloodlightModuleContext * again. * @param ecs */ public void setEntityClassifier(IEntityClassifierService ecs) { this.entityClassifier = ecs; this.startUp(null); } /** * Learn a device using the given characteristics. * @param macAddress the MAC * @param vlan the VLAN (can be null) * @param ipv4Address the IP (can be null) * @param switchDPID the attachment point switch DPID (can be null) * @param switchPort the attachment point switch port (can be null) * @param processUpdates if false, will not send updates. Note that this * method is not thread safe if this is false * @return the device, either new or not */ public IDevice learnEntity(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort, boolean processUpdates) { Set listeners = deviceListeners; if (!processUpdates) { deviceListeners = Collections.emptySet(); } if (vlan != null && vlan.shortValue() <= 0) vlan = null; if (ipv4Address != null && ipv4Address == 0) ipv4Address = null; IDevice res = learnDeviceByEntity(new Entity(macAddress, vlan, ipv4Address, switchDPID, switchPort, new Date())); deviceListeners = listeners; return res; } /** * Learn a device using the given characteristics. * @param macAddress the MAC * @param vlan the VLAN (can be null) * @param ipv4Address the IP (can be null) * @param switchDPID the attachment point switch DPID (can be null) * @param switchPort the attachment point switch port (can be null) * @return the device, either new or not */ public IDevice learnEntity(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, Integer switchPort) { return learnEntity(macAddress, vlan, ipv4Address, switchDPID, switchPort, true); } @Override protected Device allocateDevice(Long deviceKey, Entity entity, IEntityClass entityClass) { return new MockDevice(this, deviceKey, entity, entityClass); } @Override protected Device allocateDevice(Long deviceKey, List aps, List trueAPs, Collection entities, IEntityClass entityClass) { return new MockDevice(this, deviceKey, aps, trueAPs, entities, entityClass); } @Override protected Device allocateDevice(Device device, Entity entity) { return new MockDevice(device, entity); } } floodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java0000664000175000017500000000633412041336206032415 0ustar jamespagejamespage/** * Copyright 2011,2012 Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.devicemanager.test; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.TreeSet; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.SwitchPort; import net.floodlightcontroller.devicemanager.internal.AttachmentPoint; import net.floodlightcontroller.devicemanager.internal.Device; import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl; import net.floodlightcontroller.devicemanager.internal.Entity; /** * This mock device removes the dependency on topology and a parent device * manager and simply assumes all its entities are current and correct */ public class MockDevice extends Device { public MockDevice(DeviceManagerImpl deviceManager, Long deviceKey, Entity entity, IEntityClass entityClass) { super(deviceManager, deviceKey, entity, entityClass); } public MockDevice(Device device, Entity newEntity) { super(device, newEntity); } public MockDevice(DeviceManagerImpl deviceManager, Long deviceKey, List aps, List trueAPs, Collection entities, IEntityClass entityClass) { super(deviceManager, deviceKey, aps, trueAPs, entities, entityClass); } @Override public Integer[] getIPv4Addresses() { TreeSet vals = new TreeSet(); for (Entity e : entities) { if (e.getIpv4Address() == null) continue; vals.add(e.getIpv4Address()); } return vals.toArray(new Integer[vals.size()]); } @Override public SwitchPort[] getAttachmentPoints() { ArrayList vals = new ArrayList(entities.length); for (Entity e : entities) { if (e.getSwitchDPID() != null && e.getSwitchPort() != null && deviceManager.isValidAttachmentPoint(e.getSwitchDPID(), e.getSwitchPort())) { SwitchPort sp = new SwitchPort(e.getSwitchDPID(), e.getSwitchPort()); vals.add(sp); } } return vals.toArray(new SwitchPort[vals.size()]); } @Override public String toString() { String rv = "MockDevice[entities=+"; rv += entities.toString(); rv += "]"; return rv; } } floodlight-0.90/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java0000664000175000017500000000331212041336206034470 0ustar jamespagejamespagepackage net.floodlightcontroller.devicemanager.test; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; import java.util.EnumSet; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.internal.Entity; /** A simple IEntityClassifier. Useful for tests that need IEntityClassifiers * and IEntityClass'es with switch and/or port key fields */ public class MockEntityClassifier extends DefaultEntityClassifier { public static class TestEntityClass implements IEntityClass { @Override public EnumSet getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } @Override public String getName() { return "TestEntityClass"; } } public static IEntityClass testEC = new MockEntityClassifier.TestEntityClass(); @Override public IEntityClass classifyEntity(Entity entity) { if (entity.getSwitchDPID() >= 10L) { return testEC; } return DefaultEntityClassifier.entityClass; } @Override public EnumSet getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } }floodlight-0.90/src/test/java/net/floodlightcontroller/staticflowentry/0000775000175000017500000000000012041336206027223 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/staticflowentry/StaticFlowTests.java0000664000175000017500000003416012041336206033174 0ustar jamespagejamespagepackage net.floodlightcontroller.staticflowentry; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.easymock.Capture; import org.easymock.CaptureType; import org.junit.Test; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPort; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.util.HexString; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import static net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher.*; import static org.easymock.EasyMock.*; public class StaticFlowTests extends FloodlightTestCase { static String TestSwitch1DPID = "00:00:00:00:00:00:00:01"; static int TotalTestRules = 3; /*** * Create TestRuleXXX and the corresponding FlowModXXX * for X = 1..3 */ static Map TestRule1; static OFFlowMod FlowMod1; static { FlowMod1 = new OFFlowMod(); TestRule1 = new HashMap(); TestRule1.put(COLUMN_NAME, "TestRule1"); TestRule1.put(COLUMN_SWITCH, TestSwitch1DPID); // setup match OFMatch match = new OFMatch(); TestRule1.put(COLUMN_DL_DST, "00:20:30:40:50:60"); match.fromString("dl_dst=00:20:30:40:50:60"); // setup actions List actions = new LinkedList(); TestRule1.put(COLUMN_ACTIONS, "output=1"); actions.add(new OFActionOutput((short)1, (short) Short.MAX_VALUE)); // done FlowMod1.setMatch(match); FlowMod1.setActions(actions); FlowMod1.setBufferId(-1); FlowMod1.setOutPort(OFPort.OFPP_NONE.getValue()); FlowMod1.setPriority(Short.MAX_VALUE); FlowMod1.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions } static Map TestRule2; static OFFlowMod FlowMod2; static { FlowMod2 = new OFFlowMod(); TestRule2 = new HashMap(); TestRule2.put(COLUMN_NAME, "TestRule2"); TestRule2.put(COLUMN_SWITCH, TestSwitch1DPID); // setup match OFMatch match = new OFMatch(); TestRule2.put(COLUMN_NW_DST, "192.168.1.0/24"); match.fromString("nw_dst=192.168.1.0/24"); // setup actions List actions = new LinkedList(); TestRule2.put(COLUMN_ACTIONS, "output=1"); actions.add(new OFActionOutput((short)1, (short) Short.MAX_VALUE)); // done FlowMod2.setMatch(match); FlowMod2.setActions(actions); FlowMod2.setBufferId(-1); FlowMod2.setOutPort(OFPort.OFPP_NONE.getValue()); FlowMod2.setPriority(Short.MAX_VALUE); FlowMod2.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions } static Map TestRule3; static OFFlowMod FlowMod3; static { FlowMod3 = new OFFlowMod(); TestRule3 = new HashMap(); TestRule3.put(COLUMN_NAME, "TestRule3"); TestRule3.put(COLUMN_SWITCH, TestSwitch1DPID); // setup match OFMatch match = new OFMatch(); TestRule3.put(COLUMN_DL_DST, "00:20:30:40:50:60"); TestRule3.put(COLUMN_DL_VLAN, 4096); match.fromString("dl_dst=00:20:30:40:50:60,dl_vlan=4096"); // setup actions TestRule3.put(COLUMN_ACTIONS, "output=controller"); List actions = new LinkedList(); actions.add(new OFActionOutput(OFPort.OFPP_CONTROLLER.getValue(), (short) Short.MAX_VALUE)); // done FlowMod3.setMatch(match); FlowMod3.setActions(actions); FlowMod3.setBufferId(-1); FlowMod3.setOutPort(OFPort.OFPP_NONE.getValue()); FlowMod3.setPriority(Short.MAX_VALUE); FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions } private void verifyFlowMod(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { verifyMatch(testFlowMod, goodFlowMod); verifyActions(testFlowMod, goodFlowMod); // dont' bother testing the cookie; just copy it over goodFlowMod.setCookie(testFlowMod.getCookie()); // .. so we can continue to use .equals() assertEquals(goodFlowMod, testFlowMod); } private void verifyMatch(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { assertEquals(goodFlowMod.getMatch(), testFlowMod.getMatch()); } private void verifyActions(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { List goodActions = goodFlowMod.getActions(); List testActions = testFlowMod.getActions(); assertNotNull(goodActions); assertNotNull(testActions); assertEquals(goodActions.size(), testActions.size()); // assumes actions are marshalled in same order; should be safe for(int i = 0; i < goodActions.size(); i++) { assertEquals(goodActions.get(i), testActions.get(i)); } } @Override public void setUp() throws Exception { super.setUp(); } @Test public void testStaticFlowPush() throws IOException { StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher(); IStorageSourceService storage = createStorageWithFlowEntries(); long dpid = HexString.toLong(TestSwitch1DPID); // Create a Switch and attach a switch IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class); Capture writeCapture = new Capture(CaptureType.ALL); Capture contextCapture = new Capture(CaptureType.ALL); Capture> writeCaptureList = new Capture>(CaptureType.ALL); //OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class); mockSwitch.write(capture(writeCapture), capture(contextCapture)); expectLastCall().anyTimes(); mockSwitch.write(capture(writeCaptureList), capture(contextCapture)); expectLastCall().anyTimes(); mockSwitch.flush(); expectLastCall().anyTimes(); staticFlowEntryPusher.setStorageSource(storage); FloodlightModuleContext fmc = new FloodlightModuleContext(); MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider(); Map switchMap = new HashMap(); switchMap.put(dpid, mockSwitch); // NO ! expect(mockFloodlightProvider.getSwitches()).andReturn(switchMap).anyTimes(); mockFloodlightProvider.setSwitches(switchMap); staticFlowEntryPusher.setFloodlightProvider(mockFloodlightProvider); RestApiServer restApi = new RestApiServer(); try { restApi.init(fmc); } catch (FloodlightModuleException e) { e.printStackTrace(); } staticFlowEntryPusher.restApi = restApi; staticFlowEntryPusher.startUp(null); // again, to hack unittest // verify that flowpusher read all three entries from storage assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries()); // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead //expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes(); // if someone calls getId(), return this dpid instead expect(mockSwitch.getId()).andReturn(dpid).anyTimes(); expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes(); replay(mockSwitch); // hook the static pusher up to the fake switch staticFlowEntryPusher.addedSwitch(mockSwitch); verify(mockSwitch); // Verify that the switch has gotten some flow_mods assertEquals(true, writeCapture.hasCaptured()); assertEquals(TotalTestRules, writeCapture.getValues().size()); // Order assumes how things are stored in hash bucket; // should be fixed because OFMessage.hashCode() is deterministic OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2); verifyFlowMod(firstFlowMod, FlowMod1); OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1); verifyFlowMod(secondFlowMod, FlowMod2); OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0); verifyFlowMod(thirdFlowMod, FlowMod3); writeCapture.reset(); contextCapture.reset(); // delete two rules and verify they've been removed // this should invoke staticFlowPusher.rowsDeleted() storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1"); storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2"); assertEquals(1, staticFlowEntryPusher.countEntries()); assertEquals(2, writeCapture.getValues().size()); OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0); FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(firstDelete, FlowMod1); OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1); FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(secondDelete, FlowMod2); // add rules back to make sure that staticFlowPusher.rowsInserted() works writeCapture.reset(); FlowMod2.setCommand(OFFlowMod.OFPFC_ADD); storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2); assertEquals(2, staticFlowEntryPusher.countEntries()); assertEquals(1, writeCaptureList.getValues().size()); List outList = (List) writeCaptureList.getValues().get(0); assertEquals(1, outList.size()); OFFlowMod firstAdd = (OFFlowMod) outList.get(0); verifyFlowMod(firstAdd, FlowMod2); writeCapture.reset(); contextCapture.reset(); writeCaptureList.reset(); // now try an update, calling staticFlowPusher.rowUpdated() TestRule3.put(COLUMN_DL_VLAN, 333); storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); assertEquals(2, staticFlowEntryPusher.countEntries()); assertEquals(1, writeCaptureList.getValues().size()); outList = (List) writeCaptureList.getValues().get(0); assertEquals(2, outList.size()); OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0); FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); verifyFlowMod(removeFlowMod, FlowMod3); FlowMod3.setCommand(OFFlowMod.OFPFC_ADD); FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333"); OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1); verifyFlowMod(updateFlowMod, FlowMod3); } IStorageSourceService createStorageWithFlowEntries() { return populateStorageWithFlowEntries(new MemoryStorageSource()); } IStorageSourceService populateStorageWithFlowEntries(IStorageSourceService storage) { Set indexedColumns = new HashSet(); indexedColumns.add(COLUMN_NAME); storage.createTable(StaticFlowEntryPusher.TABLE_NAME, indexedColumns); storage.setTablePrimaryKeyName(StaticFlowEntryPusher.TABLE_NAME, COLUMN_NAME); storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule1); storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2); storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); return storage; } @Test public void testHARoleChanged() throws IOException { StaticFlowEntryPusher staticFlowEntryPusher = new StaticFlowEntryPusher(); IStorageSourceService storage = createStorageWithFlowEntries(); MockFloodlightProvider mfp = getMockFloodlightProvider(); staticFlowEntryPusher.setFloodlightProvider(mfp); staticFlowEntryPusher.setStorageSource(storage); RestApiServer restApi = new RestApiServer(); try { FloodlightModuleContext fmc = new FloodlightModuleContext(); restApi.init(fmc); } catch (FloodlightModuleException e) { e.printStackTrace(); } staticFlowEntryPusher.restApi = restApi; staticFlowEntryPusher.startUp(null); // again, to hack unittest assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3)); // Send a notification that we've changed to slave mfp.dispatchRoleChanged(null, Role.SLAVE); // Make sure we've removed all our entries assert(staticFlowEntryPusher.entry2dpid.isEmpty()); assert(staticFlowEntryPusher.entriesFromStorage.isEmpty()); // Send a notification that we've changed to master mfp.dispatchRoleChanged(Role.SLAVE, Role.MASTER); // Make sure we've learned the entries assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2)); assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/0000775000175000017500000000000012041336206025231 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/packet/PacketTest.java0000664000175000017500000001205612041336206030147 0ustar jamespagejamespagepackage net.floodlightcontroller.packet; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class PacketTest { protected IPacket pkt1, pkt2, pkt3, pkt4; protected IPacket dummyPkt; protected IPacket[] packets; @Before public void setUp() { this.pkt1 = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.pkt2 = new Ethernet() .setSourceMACAddress("00:44:33:22:11:01") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setVlanID((short)5) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); this.pkt3 = new Ethernet() .setSourceMACAddress("00:44:33:22:11:01") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); this.pkt4 = new Ethernet() .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") .setSourceMACAddress("00:11:33:55:77:01") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.10.1") .setDestinationAddress("192.168.255.255") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.dummyPkt = new IPv4() .setTtl((byte) 32) .setSourceAddress("1.2.3.4") .setDestinationAddress("5.6.7.8"); this.packets = new IPacket[] { pkt1, pkt2, pkt3, pkt4 }; } protected void doTestClone(IPacket pkt) { if (pkt.getPayload() != null) doTestClone(pkt.getPayload()); IPacket newPkt = (IPacket)pkt.clone(); assertSame(pkt.getClass(), newPkt.getClass()); assertNotSame(pkt, newPkt); assertSame(pkt.getParent(), newPkt.getParent()); assertEquals(pkt, newPkt); assertEquals(pkt.getPayload(), newPkt.getPayload()); if (pkt.getPayload() != null) assertNotSame(pkt.getPayload(), newPkt.getPayload()); if (pkt instanceof Ethernet) { Ethernet eth = (Ethernet)pkt; Ethernet newEth = (Ethernet)newPkt; newEth.setDestinationMACAddress(new byte[] { 1,2,3,4,5,6}); assertEquals(false, newEth.getDestinationMAC() .equals(eth.getDestinationMAC())); assertEquals(false, newPkt.equals(pkt)); } if (pkt instanceof ARP) { ARP arp = (ARP)pkt; ARP newArp = (ARP)newPkt; newArp.setSenderProtocolAddress(new byte[] {1,2,3,4}); assertEquals(false, newArp.getSenderProtocolAddress() .equals(arp.getSenderProtocolAddress())); assertEquals(false, newPkt.equals(pkt)); } byte[] dummyData = dummyPkt.serialize().clone(); newPkt = (IPacket)pkt.clone(); newPkt.deserialize(dummyData, 0, dummyData.length); assertEquals(false, newPkt.equals(pkt)); } @Test public void testClone() { for (IPacket pkt: packets) { doTestClone(pkt); } } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/ICMPTest.java0000664000175000017500000000457412041336206027476 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * @author shudong.zhou@bigswitch.com */ public class ICMPTest { private byte[] pktSerialized = new byte[] { // (byte) 0xc8, 0x2a, 0x14, 0x2d, 0x35, (byte) 0xf1, // 0x00, 0x0c, 0x29, 0x3b, (byte) 0x95, (byte) 0xf2, 0x08, 0x0, 0x45, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, (byte) 0xa3, (byte) 0xcb, (byte) 0xc0, (byte) 0xa8, (byte) 0x0a, (byte) 0xe7, (byte) 0xc0, (byte) 0xa8, (byte) 0x0a, (byte) 0xdb, 0x08, 0x00, 0x7f, 0x0a, 0x76, (byte) 0xf2, 0x00, 0x02, 0x01, 0x01, 0x01 }; @Test public void testSerialize() { IPacket packet = new IPv4() .setIdentification((short) 0) .setFlags((byte) 0x02) .setTtl((byte) 64) .setSourceAddress("192.168.10.231") .setDestinationAddress("192.168.10.219") .setPayload(new ICMP() .setIcmpType((byte) 8) .setIcmpCode((byte) 0) .setPayload(new Data(new byte[] {0x76, (byte) 0xf2, 0x0, 0x2, 0x1, 0x1, 0x1})) ); byte[] actual = packet.serialize(); assertTrue(Arrays.equals(pktSerialized, actual)); } @Test public void testDeserialize() { IPacket packet = new IPv4(); packet.deserialize(pktSerialized, 0, pktSerialized.length); byte[] pktSerialized1 = packet.serialize(); assertTrue(Arrays.equals(pktSerialized, pktSerialized1)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/IPv4Test.java0000664000175000017500000000664712041336206027533 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Assert; import org.junit.Test; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class IPv4Test { @Test public void testToIPv4Address() { int intIp = 0xc0a80001; String stringIp = "192.168.0.1"; byte[] byteIp = new byte[] {(byte)192, (byte)168, (byte)0, (byte)1}; assertEquals(intIp, IPv4.toIPv4Address(stringIp)); assertEquals(intIp, IPv4.toIPv4Address(byteIp)); assertTrue(Arrays.equals(byteIp, IPv4.toIPv4AddressBytes(intIp))); assertTrue(Arrays.equals(byteIp, IPv4.toIPv4AddressBytes(stringIp))); } @Test public void testToIPv4AddressBytes() { byte[] expected = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; Assert.assertArrayEquals(expected, IPv4.toIPv4AddressBytes("255.255.255.255")); expected = new byte[] {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80}; Assert.assertArrayEquals(expected, IPv4.toIPv4AddressBytes("128.128.128.128")); expected = new byte[] {0x7f,0x7f,0x7f,0x7f}; Assert.assertArrayEquals(expected, IPv4.toIPv4AddressBytes("127.127.127.127")); } @Test public void testSerialize() { byte[] expected = new byte[] { 0x45, 0x00, 0x00, 0x14, 0x5e, 0x4e, 0x00, 0x00, 0x3f, 0x06, 0x31, 0x2e, (byte) 0xac, 0x18, 0x4a, (byte) 0xdf, (byte) 0xab, 0x40, 0x4a, 0x30 }; IPv4 packet = new IPv4() .setIdentification((short) 24142) .setTtl((byte) 63) .setProtocol((byte) 0x06) .setSourceAddress("172.24.74.223") .setDestinationAddress("171.64.74.48"); byte[] actual = packet.serialize(); assertTrue(Arrays.equals(expected, actual)); } @Test public void testDeserialize() { // A real TLSv1 packet byte[] pktSerialized = new byte[] { 0x45, 0x00, 0x00, 0x2e, 0x41, (byte) 0xbe, 0x40, 0x00, 0x40, 0x06, (byte) 0xd4, (byte) 0xf0, (byte) 0xc0, (byte) 0xa8, 0x02, (byte) 0xdb, (byte) 0xd0, 0x55, (byte) 0x90, 0x42, (byte) 0xd5, 0x48, 0x01, (byte) 0xbb, (byte) 0xe3, 0x50, (byte) 0xb2, 0x2f, (byte) 0xfc, (byte) 0xf8, (byte) 0xa8, 0x2c, 0x50, 0x18, (byte) 0xff, (byte) 0xff, 0x24, 0x3c, 0x00, 0x00, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01 }; IPv4 packet = new IPv4(); packet.deserialize(pktSerialized, 0, pktSerialized.length); byte[] pktSerialized1 = packet.serialize(); assertTrue(Arrays.equals(pktSerialized, pktSerialized1)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/LLDPOrganizationalTLVTest.java0000664000175000017500000000645512041336206032771 0ustar jamespagejamespage/** * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.packet; import org.junit.Test; import java.nio.ByteBuffer; import java.nio.charset.Charset; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; public class LLDPOrganizationalTLVTest { private final byte[] expected = new byte[] { // Type: 127, Length: 13 (byte) 254, 13, // OpenFlow OUI: 00-26-E1 0x0, 0x26, (byte)0xe1, // SubType: 12 0xc, // Bytes in "ExtraInfo" 0x45, 0x78, 0x74, 0x72, 0x61, 0x49, 0x6e, 0x66, 0x6f }; @Test(expected = IllegalArgumentException.class) public void testShortOUI() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setOUI(new byte[2]); } @Test(expected = IllegalArgumentException.class) public void testLongOUI() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setOUI(new byte[4]); } @Test(expected = IllegalArgumentException.class) public void testLongInfoString() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setInfoString(new byte[LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH + 1]); } @Test public void testMaxInfoString() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setInfoString(new byte[LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH]); } @Test public void testInfoString() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setInfoString("ExtraInfo"); assertThat(tlv.getInfoString(), is("ExtraInfo".getBytes(Charset.forName("UTF-8")))); } @Test public void testSerialize() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.setLength((short) 13); // OpenFlow OUI is 00-26-E1 tlv.setOUI(new byte[] {0x0, 0x26, (byte) 0xe1}); tlv.setSubType((byte) 12); tlv.setInfoString("ExtraInfo".getBytes(Charset.forName("UTF-8"))); assertThat(tlv.getType(), is((byte)127)); assertThat(tlv.getLength(), is((short)13)); assertThat(tlv.getOUI(), is(new byte[] {0x0, 0x26, (byte) 0xe1})); assertThat(tlv.getSubType(), is((byte)12)); assertThat(tlv.serialize(), is(expected)); } @Test public void testDeserialize() { LLDPOrganizationalTLV tlv = new LLDPOrganizationalTLV(); tlv.deserialize(ByteBuffer.wrap(expected)); assertThat(tlv.getType(), is((byte)127)); assertThat(tlv.getLength(), is((short)13)); assertThat(tlv.getOUI(), is(new byte[] {0x0, 0x26, (byte) 0xe1})); assertThat(tlv.getSubType(), is((byte)12)); assertThat(tlv.getInfoString(), is("ExtraInfo".getBytes(Charset.forName("UTF-8")))); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/UDPTest.java0000664000175000017500000000351012041336206027363 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class UDPTest { @Test public void testSerialize() { byte[] expected = new byte[] { 0x45, 0x00, 0x00, 0x1d, 0x56, 0x23, 0x00, 0x00, (byte) 0x80, 0x11, 0x48, 0x7f, (byte) 0xc0, (byte) 0xa8, 0x01, 0x02, 0x0c, (byte) 0x81, (byte) 0xce, 0x02, 0x17, (byte) 0xe1, 0x04, 0x5f, 0x00, 0x09, 0x46, 0x6e, 0x01 }; IPacket packet = new IPv4() .setIdentification((short) 22051) .setTtl((byte) 128) .setSourceAddress("192.168.1.2") .setDestinationAddress("12.129.206.2") .setPayload(new UDP() .setSourcePort((short) 6113) .setDestinationPort((short) 1119) .setPayload(new Data(new byte[] {0x01})) ); byte[] actual = packet.serialize(); assertTrue(Arrays.equals(expected, actual)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/LLDPTest.java0000775000175000017500000000503312041336206027473 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class LLDPTest { protected byte[] pkt = {0x01,0x23,0x20,0x00,0x00,0x01,0x00,0x12,(byte) 0xe2,0x78,0x67,0x78,(byte) 0x88,(byte) 0xcc,0x02,0x07, 0x04,0x00,0x12,(byte) 0xe2,0x78,0x67,0x64,0x04,0x03,0x02,0x00,0x06,0x06,0x02,0x00,0x78, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; protected IPacket getPacket() { return new Ethernet() .setPad(true) .setDestinationMACAddress("01:23:20:00:00:01") .setSourceMACAddress("00:12:e2:78:67:78") .setEtherType(Ethernet.TYPE_LLDP) .setPayload( new LLDP() .setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) 7).setValue(new byte[] {0x04, 0x00, 0x12, (byte) 0xe2, 0x78, 0x67, 0x64})) .setPortId(new LLDPTLV().setType((byte) 2).setLength((short) 3).setValue(new byte[] {0x02, 0x00, 0x06})) .setTtl(new LLDPTLV().setType((byte) 3).setLength((short) 2).setValue(new byte[] {0x00, 0x78})) ); } @Test public void testSerialize() throws Exception { IPacket ethernet = getPacket(); assertTrue(Arrays.equals(pkt, ethernet.serialize())); } @Test public void testDeserialize() throws Exception { Ethernet ethernet = (Ethernet) new Ethernet().deserialize(pkt, 0, pkt.length); ethernet.setPad(true); assertTrue(Arrays.equals(pkt, ethernet.serialize())); IPacket expected = getPacket(); assertEquals(expected, ethernet); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/TCPTest.java0000664000175000017500000000534312041336206027367 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * @author shudong.zhou@bigswitch.com */ public class TCPTest { private byte[] pktSerialized = new byte[] { 0x45, 0x20, 0x00, 0x34, 0x1d, (byte) 0x85, 0x00, 0x00, 0x32, 0x06, 0x31, 0x1e, 0x4a, 0x7d, 0x2d, 0x6d, (byte) 0xc0, (byte) 0xa8, 0x01, 0x6f, 0x03, (byte) 0xe1, (byte) 0xc0, 0x32, (byte) 0xe3, (byte) 0xad, (byte) 0xee, (byte) 0x88, (byte) 0xb7, (byte) 0xda, (byte) 0xd8, 0x24, (byte) 0x80, 0x10, 0x01, 0x0b, 0x59, 0x33, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x20, (byte) 0x9a, 0x41, 0x04, 0x07, 0x76, 0x53, 0x1f}; @Test public void testSerialize() { IPacket packet = new IPv4() .setDiffServ((byte) 0x20) .setIdentification((short) 0x1d85) .setFlags((byte) 0x00) .setTtl((byte) 50) .setSourceAddress("74.125.45.109") .setDestinationAddress("192.168.1.111") .setPayload(new TCP() .setSourcePort((short) 993) .setDestinationPort((short) 49202) .setSequence(0xe3adee88) .setAcknowledge(0xb7dad824) .setDataOffset((byte) 8) .setFlags((short) 0x10) .setWindowSize((short) 267) .setOptions(new byte[] {0x01, 0x01, 0x08, 0x0a, 0x20, (byte) 0x9a, 0x41, 0x04, 0x07, 0x76, 0x53, 0x1f}) .setPayload(null) ); byte[] actual = packet.serialize(); assertTrue(Arrays.equals(pktSerialized, actual)); } @Test public void testDeserialize() { IPacket packet = new IPv4(); packet.deserialize(pktSerialized, 0, pktSerialized.length); byte[] pktSerialized1 = packet.serialize(); assertTrue(Arrays.equals(pktSerialized, pktSerialized1)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/DHCPTest.java0000664000175000017500000011441012041336206027453 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import java.util.Arrays; import java.util.ListIterator; import junit.framework.TestCase; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class DHCPTest extends TestCase { public byte[] dhcpPacket = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0x66, (byte) 0xf2, (byte) 0x8a, (byte) 0x11, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9f, (byte) 0xfe, (byte) 0xd8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x01, (byte) 0x37, (byte) 0x0a, (byte) 0x01, (byte) 0x1c, (byte) 0x02, (byte) 0x03, (byte) 0x0f, (byte) 0x06, (byte) 0x0c, (byte) 0x28, (byte) 0x29, (byte) 0x2a, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; public byte[] dhcpPacket2 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9e, (byte) 0x11, (byte) 0x84, (byte) 0x08, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x02, (byte) 0x40, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x11, (byte) 0xa4, (byte) 0xaa, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43, (byte) 0x02, (byte) 0x2c, (byte) 0xdd, (byte) 0x9d, (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0xa4, (byte) 0x9e, (byte) 0x11, (byte) 0x84, (byte) 0x00, (byte) 0x40, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9e, (byte) 0x11, (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x01, (byte) 0x37, (byte) 0x18, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x05, (byte) 0x06, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0f, (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x2b, (byte) 0x36, (byte) 0x3c, (byte) 0x43, (byte) 0x80, (byte) 0x81, (byte) 0x82, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87, (byte) 0x39, (byte) 0x02, (byte) 0x04, (byte) 0xec, (byte) 0x61, (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x5d, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x5e, (byte) 0x03, (byte) 0x01, (byte) 0x02, (byte) 0x01, (byte) 0x3c, (byte) 0x20, (byte) 0x50, (byte) 0x58, (byte) 0x45, (byte) 0x43, (byte) 0x6c, (byte) 0x69, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x3a, (byte) 0x41, (byte) 0x72, (byte) 0x63, (byte) 0x68, (byte) 0x3a, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x3a, (byte) 0x55, (byte) 0x4e, (byte) 0x44, (byte) 0x49, (byte) 0x3a, (byte) 0x30, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0x30, (byte) 0x31, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; public byte[] dhcpPacket3 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x74, (byte) 0x44, (byte) 0x01, (byte) 0x72, (byte) 0xd8, (byte) 0x41, (byte) 0x08, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x01, (byte) 0x1f, (byte) 0x48, (byte) 0xcd, (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x11, (byte) 0x6f, (byte) 0x6a, (byte) 0xc0, (byte) 0xa8, (byte) 0x00, (byte) 0xef, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43, (byte) 0x01, (byte) 0x0b, (byte) 0xb3, (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0x82, (byte) 0x88, (byte) 0xa6, (byte) 0xc9, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x74, (byte) 0x44, (byte) 0x01, (byte) 0x72, (byte) 0xd8, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x01, (byte) 0x32, (byte) 0x04, (byte) 0xc0, (byte) 0xa8, (byte) 0x0a, (byte) 0xa9, (byte) 0x39, (byte) 0x02, (byte) 0x02, (byte) 0x40, (byte) 0x37, (byte) 0x03, (byte) 0x01, (byte) 0x03, (byte) 0x06, (byte) 0xff }; public byte[] dhcpPacketPXE = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x19, (byte) 0xb9, (byte) 0xb0, (byte) 0x01, (byte) 0x44, (byte) 0x08, (byte) 0x00, (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x48, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x11, (byte) 0x2c, (byte) 0x98, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x43, (byte) 0x00, (byte) 0x44, (byte) 0x01, (byte) 0x34, (byte) 0xa6, (byte) 0xf0, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0xa0, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x04, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x65, (byte) 0x6e, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x5f, (byte) 0x35, (byte) 0x2e, (byte) 0x36, (byte) 0x2f, (byte) 0x70, (byte) 0x78, (byte) 0x65, (byte) 0x6c, (byte) 0x69, (byte) 0x6e, (byte) 0x75, (byte) 0x78, (byte) 0x2e, (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x02, (byte) 0x36, (byte) 0x04, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0x33, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0xa8, (byte) 0xc0, (byte) 0x01, (byte) 0x04, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x03, (byte) 0x04, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0x0c, (byte) 0x0d, (byte) 0x64, (byte) 0x6e, (byte) 0x72, (byte) 0x63, (byte) 0x2d, (byte) 0x68, (byte) 0x6f, (byte) 0x73, (byte) 0x74, (byte) 0x30, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; public byte[] dhcpPacketBadOption1 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x19, (byte) 0xb9, (byte) 0xb0, (byte) 0x01, (byte) 0x44, (byte) 0x08, (byte) 0x00, (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x48, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x11, (byte) 0x2c, (byte) 0x98, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43, (byte) 0x01, (byte) 0x34, (byte) 0xa6, (byte) 0xf0, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0xa0, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x04, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x65, (byte) 0x6e, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x5f, (byte) 0x35, (byte) 0x2e, (byte) 0x36, (byte) 0x2f, (byte) 0x70, (byte) 0x78, (byte) 0x65, (byte) 0x6c, (byte) 0x69, (byte) 0x6e, (byte) 0x75, (byte) 0x78, (byte) 0x2e, (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x01, (byte) 0x36, (byte) 0x04, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0x33, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0xa8, (byte) 0xc0, (byte) 0x01, (byte) 0x04, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x03, (byte) 0x04, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0x0c, (byte) 0x30, (byte) 0x64, (byte) 0x6e, (byte) 0x72, (byte) 0x63, (byte) 0x2d, (byte) 0x68, (byte) 0x6f, (byte) 0x73, (byte) 0x74, (byte) 0x30, (byte) 0x30, (byte) 0x32, (byte) 0x30, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; public byte[] dhcpPacketBadHeader = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x19, (byte) 0xb9, (byte) 0xb0, (byte) 0x01, (byte) 0x44, (byte) 0x08, (byte) 0x00, (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x48, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x11, (byte) 0x2c, (byte) 0x98, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43, (byte) 0x01, (byte) 0x34, (byte) 0xa6, (byte) 0xf0, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00, (byte) 0xa0, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x04, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0a, (byte) 0x00, (byte) 0x02, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x9f, (byte) 0x9e, (byte) 0x0c, (byte) 0x13, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x78, (byte) 0x65, (byte) 0x6e, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, (byte) 0x5f, (byte) 0x35, (byte) 0x2e, (byte) 0x36, (byte) 0x2f, (byte) 0x70, (byte) 0x78, (byte) 0x65, (byte) 0x6c, (byte) 0x69, (byte) 0x6e, (byte) 0x75, (byte) 0x78, (byte) 0x2e, (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; private void resetChecksumsAndLengths(IPv4 ipv4, UDP udp) { ipv4.setChecksum((short)0); udp.setChecksum((short)0); } public void testSerialize() { DHCP dhcp = new DHCP(); dhcp.deserialize(dhcpPacket, 0, dhcpPacket.length); byte[] result = dhcp.serialize(); assertTrue(Arrays.equals(this.dhcpPacket, result)); } public void testDeSerialize() { Ethernet eth = new Ethernet(); eth.deserialize(dhcpPacket2, 0, dhcpPacket2.length); assertTrue(eth.getPayload() instanceof IPv4); IPv4 ipv4 = (IPv4) eth.getPayload(); assertTrue(ipv4.getPayload() instanceof UDP); UDP udp = (UDP) ipv4.getPayload(); assertTrue(udp.getPayload() instanceof DHCP); DHCP dhcp = (DHCP) udp.getPayload(); /** The invalid option in DHCP packet is dropped. Reset checksums and * length field so that the serialize() function can re-compute them */ resetChecksumsAndLengths(ipv4, udp); assertEquals(DHCP.OPCODE_REQUEST, dhcp.getOpCode()); } public void testDeSerializeReSerialize() { Ethernet eth = new Ethernet(); eth.deserialize(dhcpPacket3, 0, dhcpPacket3.length); assertTrue(eth.getPayload() instanceof IPv4); IPv4 ipv4 = (IPv4) eth.getPayload(); assertTrue(ipv4.getPayload() instanceof UDP); byte[] serializedPacket = eth.serialize(); Ethernet eth2 = new Ethernet(); eth2.deserialize(serializedPacket, 0, serializedPacket.length); IPv4 ipv42 = (IPv4) eth2.getPayload(); short ipchecksum = ipv42.getChecksum(); ipv42.setChecksum((short) 0); eth2.serialize(); assertEquals(ipchecksum, ipv42.getChecksum()); } public void testDeSerializePXE() { Ethernet eth = new Ethernet(); eth.deserialize(dhcpPacketPXE, 0, dhcpPacketPXE.length); assertTrue(eth.getPayload() instanceof IPv4); IPv4 ipv4 = (IPv4) eth.getPayload(); assertTrue(ipv4.getPayload() instanceof UDP); UDP udp = (UDP) ipv4.getPayload(); assertTrue(udp.getPayload() instanceof DHCP); DHCP dhcp = (DHCP) udp.getPayload(); /** The invalid option in DHCP packet is dropped. Reset checksums and * length field so that the serialize() function can re-compute them */ resetChecksumsAndLengths(ipv4, udp); assertEquals(DHCP.OPCODE_REPLY, dhcp.getOpCode()); assertEquals("xenserver_5.6/pxelinux.0", dhcp.getBootFileName()); byte[] result = eth.serialize(); assertTrue(Arrays.equals(this.dhcpPacketPXE, result)); } public void testDeSerializeBad1() { Ethernet eth = new Ethernet(); eth.deserialize(dhcpPacketBadOption1, 0, dhcpPacketBadOption1.length); assertTrue(eth.getPayload() instanceof IPv4); IPv4 ipv4 = (IPv4) eth.getPayload(); assertTrue(ipv4.getPayload() instanceof UDP); UDP udp = (UDP) ipv4.getPayload(); assertTrue(udp.getPayload() instanceof DHCP); DHCP dhcp = (DHCP) udp.getPayload(); /** The invalid option in DHCP packet is dropped. Reset checksums and * length field so that the serialize() function can re-compute them */ resetChecksumsAndLengths(ipv4, udp); assertEquals(DHCP.OPCODE_REPLY, dhcp.getOpCode()); ListIterator lit = dhcp.getOptions().listIterator(); // Expect 5 correct options and an END option. assertEquals(dhcp.getOptions().size(), 6); while (lit.hasNext()) { DHCPOption option = lit.next(); assertFalse(option.code == (byte)0x0c); } byte[] result = eth.serialize(); // Since one option is badly formated, the result is different. assertFalse(Arrays.equals(this.dhcpPacketPXE, result)); } public void testDeSerializeBadHeader() { Ethernet eth = new Ethernet(); eth.deserialize(dhcpPacketBadHeader, 0, dhcpPacketBadHeader.length); assertTrue(eth.getPayload() instanceof IPv4); IPv4 ipv4 = (IPv4) eth.getPayload(); assertTrue(ipv4.getPayload() instanceof UDP); UDP udp = (UDP) ipv4.getPayload(); assertTrue(udp.getPayload() instanceof DHCP); DHCP dhcp = (DHCP) udp.getPayload(); assertEquals(UDP.DHCP_CLIENT_PORT, udp.getSourcePort()); assertEquals(UDP.DHCP_SERVER_PORT, udp.getDestinationPort()); // should get invalid opCode of 0 assertEquals(0, dhcp.getOpCode()); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/EthernetTest.java0000664000175000017500000000504512041336206030516 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class EthernetTest { @Test public void testToMACAddress() { byte[] address = new byte[] { 0x0, 0x11, 0x22, (byte) 0xff, (byte) 0xee, (byte) 0xdd}; assertTrue(Arrays.equals(address, Ethernet .toMACAddress("00:11:22:ff:ee:dd"))); assertTrue(Arrays.equals(address, Ethernet .toMACAddress("00:11:22:FF:EE:DD"))); } @Test public void testSerialize() { Ethernet ethernet = new Ethernet() .setDestinationMACAddress("de:ad:be:ef:de:ad") .setSourceMACAddress("be:ef:de:ad:be:ef") .setEtherType((short) 0); byte[] expected = new byte[] { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, 0x0, 0x0 }; assertTrue(Arrays.equals(expected, ethernet.serialize())); } @Test public void testToLong() { assertEquals( 281474976710655L, Ethernet.toLong(new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff })); assertEquals( 1103823438081L, Ethernet.toLong(new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 })); assertEquals( 141289400074368L, Ethernet.toLong(new byte[] { (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 })); } } floodlight-0.90/src/test/java/net/floodlightcontroller/packet/BSNTest.java0000664000175000017500000000517712041336206027370 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ /** * */ package net.floodlightcontroller.packet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Arrays; import org.junit.Test; /** * * @author David Erickson (daviderickson@cs.stanford.edu) * */ public class BSNTest { protected byte[] probePkt = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // src mac 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, // dst mac (byte) 0x89, 0x42, // BSN type 0x20, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0x00, // BSN header 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // controller id 0x00, 0x00, 0x00, 0x03, // sequence id 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // src mac 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, // dst mac 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, // switch dpid 0x00, 0x00, 0x00, 0x01 // port number }; protected Ethernet getProbePacket() { return (Ethernet) new Ethernet() .setSourceMACAddress("00:00:00:00:00:04") .setDestinationMACAddress("00:00:00:00:00:01") .setEtherType(Ethernet.TYPE_BSN) .setPayload(new BSN(BSN.BSN_TYPE_PROBE) .setPayload(new BSNPROBE() .setSequenceId(3) .setSrcMac(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) .setDstMac(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}) .setSrcSwDpid(0x06) .setSrcPortNo(0x01) ) ); } @Test public void testSerialize() throws Exception { Ethernet pkt = getProbePacket(); byte[] serialized = pkt.serialize(); assertTrue(Arrays.equals(probePkt, serialized)); } @Test public void testDeserialize() throws Exception { Ethernet pkt = (Ethernet) new Ethernet().deserialize(probePkt, 0, probePkt.length); assertTrue(Arrays.equals(probePkt, pkt.serialize())); Ethernet expected = getProbePacket(); assertEquals(expected, pkt); } } floodlight-0.90/src/test/java/net/floodlightcontroller/flowcache/0000775000175000017500000000000012041336206025715 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java0000664000175000017500000004714312041336206032632 0ustar jamespagejamespagepackage net.floodlightcontroller.flowcache; import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.Date; import java.util.ListIterator; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.counter.SimpleCounter; import net.floodlightcontroller.counter.CounterValue.CounterType; import net.floodlightcontroller.flowcache.IFlowReconcileListener; import net.floodlightcontroller.flowcache.OFMatchReconcile; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.easymock.EasyMock; import org.easymock.IAnswer; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.OFType; public class FlowReconcileMgrTest extends FloodlightTestCase { protected MockFloodlightProvider mockFloodlightProvider; protected FlowReconcileManager flowReconcileMgr; protected MockThreadPoolService threadPool; protected ICounterStoreService counterStore; protected FloodlightModuleContext fmc; OFStatisticsRequest ofStatsRequest; protected int NUM_FLOWS_PER_THREAD = 100; protected int NUM_THREADS = 100; @Before public void setUp() throws Exception { super.setUp(); fmc = new FloodlightModuleContext(); flowReconcileMgr = new FlowReconcileManager(); threadPool = new MockThreadPoolService(); counterStore = createMock(ICounterStoreService.class); fmc.addService(ICounterStoreService.class, counterStore); fmc.addService(IThreadPoolService.class, threadPool); threadPool.init(fmc); flowReconcileMgr.init(fmc); threadPool.startUp(fmc); flowReconcileMgr.startUp(fmc); } /** Verify pipeline listener registration and ordering * * @throws Exception */ @SuppressWarnings("unchecked") @Test public void testFlowReconcilePipeLine() throws Exception { flowReconcileMgr.flowReconcileEnabled = true; IFlowReconcileListener r1 = EasyMock.createNiceMock(IFlowReconcileListener.class); IFlowReconcileListener r2 = EasyMock.createNiceMock(IFlowReconcileListener.class); IFlowReconcileListener r3 = EasyMock.createNiceMock(IFlowReconcileListener.class); expect(r1.getName()).andReturn("r1").anyTimes(); expect(r2.getName()).andReturn("r2").anyTimes(); expect(r3.getName()).andReturn("r3").anyTimes(); // Set the listeners' order: r1 -> r2 -> r3 expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), eq("r1"))).andReturn(true).anyTimes(); expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), eq("r3"))).andReturn(false).anyTimes(); expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), eq("r1"))).andReturn(false).anyTimes(); expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), eq("r3"))).andReturn(true).anyTimes(); expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), eq("r1"))).andReturn(false).anyTimes(); expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), eq("r2"))).andReturn(true).anyTimes(); expect(r3.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.reconcileFlows((ArrayList)anyObject())). andThrow(new RuntimeException("This is NOT an error! " + "We are testing exception catching.")); SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter( new Date(), CounterType.LONG); cnt.increment(); expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(cnt) .anyTimes(); replay(r1, r2, r3, counterStore); flowReconcileMgr.clearFlowReconcileListeners(); flowReconcileMgr.addFlowReconcileListener(r1); flowReconcileMgr.addFlowReconcileListener(r2); flowReconcileMgr.addFlowReconcileListener(r3); int pre_flowReconcileThreadRunCount = flowReconcileMgr.flowReconcileThreadRunCount; Date startTime = new Date(); OFMatchReconcile ofmRcIn = new OFMatchReconcile(); try { flowReconcileMgr.reconcileFlow(ofmRcIn); flowReconcileMgr.doReconcile(); } catch (RuntimeException e) { assertEquals(e.getMessage() .startsWith("This is NOT an error!"), true); } verify(r1, r2, r3); // verify STOP works reset(r1, r2, r3); // restart reconcileThread since it exited due to previous runtime // exception. flowReconcileMgr.startUp(fmc); expect(r1.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.STOP).times(1); expect(r2.reconcileFlows((ArrayList)anyObject())); expectLastCall().andAnswer(new IAnswer() { public Object answer() { fail("Unexpected call"); return Command.STOP; } }).anyTimes(); pre_flowReconcileThreadRunCount = flowReconcileMgr.flowReconcileThreadRunCount; startTime = new Date(); replay(r1, r2, r3); flowReconcileMgr.reconcileFlow(ofmRcIn); while (flowReconcileMgr.flowReconcileThreadRunCount <= pre_flowReconcileThreadRunCount) { Thread.sleep(10); Date currTime = new Date(); assertTrue((currTime.getTime() - startTime.getTime()) < 1000); } verify(r1, r2, r3); // verify CONTINUE works reset(r1, r2, r3); expect(r1.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.CONTINUE).times(1); expect(r2.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.STOP).times(1); expect(r3.reconcileFlows((ArrayList)anyObject())); expectLastCall().andAnswer(new IAnswer() { public Object answer() { fail("Unexpected call"); return Command.STOP; } }).anyTimes(); pre_flowReconcileThreadRunCount = flowReconcileMgr.flowReconcileThreadRunCount; startTime = new Date(); replay(r1, r2, r3); flowReconcileMgr.reconcileFlow(ofmRcIn); while (flowReconcileMgr.flowReconcileThreadRunCount <= pre_flowReconcileThreadRunCount) { Thread.sleep(10); Date currTime = new Date(); assertTrue((currTime.getTime() - startTime.getTime()) < 1000); } verify(r1, r2, r3); // verify CONTINUE works reset(r1, r2, r3); expect(r1.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.CONTINUE).times(1); expect(r2.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.CONTINUE).times(1); expect(r3.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.STOP).times(1); pre_flowReconcileThreadRunCount = flowReconcileMgr.flowReconcileThreadRunCount; startTime = new Date(); replay(r1, r2, r3); flowReconcileMgr.reconcileFlow(ofmRcIn); while (flowReconcileMgr.flowReconcileThreadRunCount <= pre_flowReconcileThreadRunCount) { Thread.sleep(10); Date currTime = new Date(); assertTrue((currTime.getTime() - startTime.getTime()) < 1000); } verify(r1, r2, r3); // Verify removeFlowReconcileListener flowReconcileMgr.removeFlowReconcileListener(r1); reset(r1, r2, r3); expect(r1.reconcileFlows((ArrayList)anyObject())); expectLastCall().andAnswer(new IAnswer() { public Object answer() { fail("Unexpected call to a listener that is " + "removed from the chain."); return Command.STOP; } }).anyTimes(); expect(r2.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.CONTINUE).times(1); expect(r3.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.STOP).times(1); pre_flowReconcileThreadRunCount = flowReconcileMgr.flowReconcileThreadRunCount; startTime = new Date(); replay(r1, r2, r3); flowReconcileMgr.reconcileFlow(ofmRcIn); while (flowReconcileMgr.flowReconcileThreadRunCount <= pre_flowReconcileThreadRunCount) { Thread.sleep(10); Date currTime = new Date(); assertTrue((currTime.getTime() - startTime.getTime()) < 1000); } verify(r1, r2, r3); } @Test public void testGetPktInRate() { internalTestGetPktInRate(CounterType.LONG); internalTestGetPktInRate(CounterType.DOUBLE); } protected void internalTestGetPktInRate(CounterType type) { Date currentTime = new Date(); SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, type); newCnt.increment(currentTime, 1); // Set the lastCounter time in the future of the current time Date lastCounterTime = new Date(currentTime.getTime() + 1000); flowReconcileMgr.lastPacketInCounter = (SimpleCounter)SimpleCounter.createCounter( lastCounterTime, type); flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1); assertEquals(FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND, flowReconcileMgr.getPktInRate(newCnt, new Date())); // Verify the rate == 0 time difference is zero. lastCounterTime = new Date(currentTime.getTime() - 1000); flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1); assertEquals(0, flowReconcileMgr.getPktInRate(newCnt, lastCounterTime)); /** verify the computation is correct. * new = 2000, old = 1000, Tdiff = 1 second. * rate should be 1000/second */ newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, type); newCnt.increment(currentTime, 2000); lastCounterTime = new Date(currentTime.getTime() - 1000); flowReconcileMgr.lastPacketInCounter = (SimpleCounter)SimpleCounter.createCounter( lastCounterTime, type); flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1000); assertEquals(1000, flowReconcileMgr.getPktInRate(newCnt, currentTime)); /** verify the computation is correct. * new = 2,000,000, old = 1,000,000, Tdiff = 2 second. * rate should be 1000/second */ newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, type); newCnt.increment(currentTime, 2000000); lastCounterTime = new Date(currentTime.getTime() - 2000); flowReconcileMgr.lastPacketInCounter = (SimpleCounter)SimpleCounter.createCounter( lastCounterTime, type); flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1000000); assertEquals(500000, flowReconcileMgr.getPktInRate(newCnt, currentTime)); } @Test public void testGetCurrentCapacity() throws Exception { // Disable the reconcile thread. flowReconcileMgr.flowReconcileEnabled = false; int minFlows = FlowReconcileManager.MIN_FLOW_RECONCILE_PER_SECOND * FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000; /** Verify the initial state, when packetIn counter has not * been created. */ expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(null) .times(1); replay(counterStore); assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity()); verify(counterStore); /** Verify the initial state, when lastPacketInCounter is null */ reset(counterStore); Date currentTime = new Date(); SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, CounterType.LONG); expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(newCnt) .times(1); long initPktInCount = 10000; newCnt.increment(currentTime, initPktInCount); replay(counterStore); assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity()); verify(counterStore); /** Now the lastPacketInCounter has been set. * lastCounter = 100,000 and newCounter = 300,000, t = 1 second * packetInRate = 200,000/sec. * capacity should be 500k - 200k = 300k */ reset(counterStore); newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, CounterType.LONG); currentTime = new Date(currentTime.getTime() + 200); long nextPktInCount = 30000; newCnt.increment(currentTime, nextPktInCount); expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(newCnt) .times(1); replay(counterStore); // Wait for 1 second so that enough elapsed time to compute capacity. Thread.sleep(1000); int capacity = flowReconcileMgr.getCurrentCapacity(); verify(counterStore); long expectedCap = (FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND - (nextPktInCount - initPktInCount)) * FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000; assertEquals(expectedCap, capacity); } private class FlowReconcileWorker implements Runnable { @Override public void run() { OFMatchReconcile ofmRc = new OFMatchReconcile(); // push large number of flows to be reconciled. for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) { flowReconcileMgr.reconcileFlow(ofmRc); } } } /** Verify the flows are sent to the reconcile pipeline in order. */ @SuppressWarnings("unchecked") @Test public void testQueueFlowsOrder() { flowReconcileMgr.flowReconcileEnabled = false; IFlowReconcileListener r1 = EasyMock.createNiceMock(IFlowReconcileListener.class); expect(r1.getName()).andReturn("r1").anyTimes(); // Set the listeners' order: r1 -> r2 -> r3 expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.reconcileFlows((ArrayList)anyObject())) .andAnswer(new IAnswer() { @Override public Command answer() throws Throwable { ArrayList ofmList = (ArrayList)EasyMock. getCurrentArguments()[0]; ListIterator lit = ofmList.listIterator(); int index = 0; while (lit.hasNext()) { OFMatchReconcile ofm = lit.next(); assertEquals(index++, ofm.cookie); } return Command.STOP; } }).times(1); SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter( new Date(), CounterType.LONG); cnt.increment(); expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(cnt) .anyTimes(); replay(r1, counterStore); flowReconcileMgr.clearFlowReconcileListeners(); flowReconcileMgr.addFlowReconcileListener(r1); OFMatchReconcile ofmRcIn = new OFMatchReconcile(); int index = 0; for (index = 0; index < 10; index++) { ofmRcIn.cookie = index; flowReconcileMgr.reconcileFlow(ofmRcIn); } flowReconcileMgr.flowReconcileEnabled = true; flowReconcileMgr.doReconcile(); verify(r1); } @SuppressWarnings("unchecked") @Test public void testQueueFlowsByManyThreads() { // Disable the reconcile thread so that the queue won't be emptied. flowQueueTest(false); // Enable the reconcile thread. The queue should be empty. Date currentTime = new Date(); SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( currentTime, CounterType.LONG); expect(counterStore.getCounter( flowReconcileMgr.controllerPktInCounterName)) .andReturn(newCnt) .anyTimes(); long initPktInCount = 10000; newCnt.increment(currentTime, initPktInCount); IFlowReconcileListener r1 = EasyMock.createNiceMock(IFlowReconcileListener.class); expect(r1.getName()).andReturn("r1").anyTimes(); // Set the listeners' order: r1 -> r2 -> r3 expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(r1.reconcileFlows((ArrayList)anyObject())) .andReturn(Command.CONTINUE).anyTimes(); flowReconcileMgr.clearFlowReconcileListeners(); replay(r1, counterStore); flowQueueTest(true); verify(r1, counterStore); } protected void flowQueueTest(boolean enableReconcileThread) { flowReconcileMgr.flowReconcileEnabled = enableReconcileThread; // Simulate flow for (int i = 0; i < NUM_THREADS; i++) { Runnable worker = this.new FlowReconcileWorker(); Thread t = new Thread(worker); t.start(); } Date startTime = new Date(); int totalFlows = NUM_THREADS * NUM_FLOWS_PER_THREAD; if (enableReconcileThread) { totalFlows = 0; } while (flowReconcileMgr.flowQueue.size() != totalFlows) { Date currTime = new Date(); assertTrue((currTime.getTime() - startTime.getTime()) < 2000); } // Make sure all flows are in the queue. assertEquals(totalFlows, flowReconcileMgr.flowQueue.size()); } } floodlight-0.90/src/test/java/net/floodlightcontroller/routing/0000775000175000017500000000000012041336206025451 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/routing/RouteTest.java0000664000175000017500000000406712041336206030261 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.routing; import org.junit.Test; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.topology.NodePortTuple; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class RouteTest extends FloodlightTestCase { @Test public void testCloneable() throws Exception { Route r1 = new Route(1L, 2L); Route r2 = new Route(1L, 3L); assertNotSame(r1, r2); assertNotSame(r1.getId(), r2.getId()); r1 = new Route(1L, 3L); r1.getPath().add(new NodePortTuple(1L, (short)1)); r1.getPath().add(new NodePortTuple(2L, (short)1)); r1.getPath().add(new NodePortTuple(2L, (short)2)); r1.getPath().add(new NodePortTuple(3L, (short)1)); r2.getPath().add(new NodePortTuple(1L, (short)1)); r2.getPath().add(new NodePortTuple(2L, (short)1)); r2.getPath().add(new NodePortTuple(2L, (short)2)); r2.getPath().add(new NodePortTuple(3L, (short)1)); assertEquals(r1, r2); NodePortTuple temp = r2.getPath().remove(0); assertNotSame(r1, r2); r2.getPath().add(0, temp); assertEquals(r1, r2); r2.getPath().remove(1); temp = new NodePortTuple(2L, (short)5); r2.getPath().add(1, temp); assertNotSame(r1, r2); } } floodlight-0.90/src/test/java/net/floodlightcontroller/forwarding/0000775000175000017500000000000012041336206026124 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java0000664000175000017500000005477112041336206031747 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.forwarding; import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.test.MockDeviceManager; import net.floodlightcontroller.counter.CounterStore; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.ITopologyListener; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import net.floodlightcontroller.flowcache.FlowReconcileManager; import net.floodlightcontroller.flowcache.IFlowReconcileService; import net.floodlightcontroller.forwarding.Forwarding; import org.easymock.Capture; import org.easymock.CaptureType; import org.easymock.EasyMock; import org.junit.Test; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.util.HexString; public class ForwardingTest extends FloodlightTestCase { protected MockFloodlightProvider mockFloodlightProvider; protected FloodlightContext cntx; protected MockDeviceManager deviceManager; protected IRoutingService routingEngine; protected Forwarding forwarding; protected FlowReconcileManager flowReconcileMgr; protected ITopologyService topology; protected MockThreadPoolService threadPool; protected IOFSwitch sw1, sw2; protected OFFeaturesReply swFeatures; protected IDevice srcDevice, dstDevice1, dstDevice2; protected OFPacketIn packetIn; protected OFPacketOut packetOut; protected OFPacketOut packetOutFlooded; protected IPacket testPacket; protected byte[] testPacketSerialized; protected int expected_wildcards; protected Date currentDate; @Override public void setUp() throws Exception { super.setUp(); cntx = new FloodlightContext(); // Module loader setup /* Collection> mods = new ArrayList>(); Collection mockedServices = new ArrayList(); mods.add(Forwarding.class); routingEngine = createMock(IRoutingService.class); topology = createMock(ITopologyService.class); mockedServices.add(routingEngine); mockedServices.add(topology); FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader(); fml.setupModules(mods, mockedServices); mockFloodlightProvider = (MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class); deviceManager = (MockDeviceManager) fml.getModuleByName(MockDeviceManager.class); threadPool = (MockThreadPoolService) fml.getModuleByName(MockThreadPoolService.class); forwarding = (Forwarding) fml.getModuleByName(Forwarding.class); */ mockFloodlightProvider = getMockFloodlightProvider(); forwarding = new Forwarding(); threadPool = new MockThreadPoolService(); deviceManager = new MockDeviceManager(); flowReconcileMgr = new FlowReconcileManager(); routingEngine = createMock(IRoutingService.class); topology = createMock(ITopologyService.class); DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); FloodlightModuleContext fmc = new FloodlightModuleContext(); fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); fmc.addService(IThreadPoolService.class, threadPool); fmc.addService(ITopologyService.class, topology); fmc.addService(IRoutingService.class, routingEngine); fmc.addService(ICounterStoreService.class, new CounterStore()); fmc.addService(IDeviceService.class, deviceManager); fmc.addService(IFlowReconcileService.class, flowReconcileMgr); fmc.addService(IEntityClassifierService.class, entityClassifier); topology.addListener(anyObject(ITopologyListener.class)); expectLastCall().anyTimes(); replay(topology); threadPool.init(fmc); forwarding.init(fmc); deviceManager.init(fmc); flowReconcileMgr.init(fmc); entityClassifier.init(fmc); threadPool.startUp(fmc); deviceManager.startUp(fmc); forwarding.startUp(fmc); flowReconcileMgr.startUp(fmc); entityClassifier.startUp(fmc); verify(topology); swFeatures = new OFFeaturesReply(); swFeatures.setBuffers(1000); // Mock switches sw1 = EasyMock.createMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getBuffers()).andReturn(swFeatures.getBuffers()).anyTimes(); expect(sw1.getStringId()) .andReturn(HexString.toHexString(1L)).anyTimes(); sw2 = EasyMock.createMock(IOFSwitch.class); expect(sw2.getId()).andReturn(2L).anyTimes(); expect(sw2.getBuffers()).andReturn(swFeatures.getBuffers()).anyTimes(); expect(sw2.getStringId()) .andReturn(HexString.toHexString(2L)).anyTimes(); //fastWilcards mocked as this constant int fastWildcards = OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS; expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer)fastWildcards).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); expect(sw2.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer)fastWildcards).anyTimes(); expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); // Load the switch map Map switches = new HashMap(); switches.put(1L, sw1); switches.put(2L, sw2); mockFloodlightProvider.setSwitches(switches); // Build test packet testPacket = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); currentDate = new Date(); // Mock Packet-in testPacketSerialized = testPacket.serialize(); packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testPacketSerialized.length); // Mock Packet-out packetOut = (OFPacketOut) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_OUT); packetOut.setBufferId(this.packetIn.getBufferId()) .setInPort(this.packetIn.getInPort()); List poactions = new ArrayList(); poactions.add(new OFActionOutput((short) 3, (short) 0xffff)); packetOut.setActions(poactions) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testPacketSerialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+ packetOut.getActionsLength()+ testPacketSerialized.length); // Mock Packet-out with OFPP_FLOOD action packetOutFlooded = (OFPacketOut) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_OUT); packetOutFlooded.setBufferId(this.packetIn.getBufferId()) .setInPort(this.packetIn.getInPort()); poactions = new ArrayList(); poactions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), (short) 0xffff)); packetOutFlooded.setActions(poactions) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testPacketSerialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+ packetOutFlooded.getActionsLength()+ testPacketSerialized.length); expected_wildcards = fastWildcards; expected_wildcards &= ~OFMatch.OFPFW_IN_PORT & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST; expected_wildcards &= ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK; IFloodlightProviderService.bcStore. put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)testPacket); } enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 }; public void learnDevices(DestDeviceToLearn destDeviceToLearn) { // Build src and dest devices byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress(); byte[] dataLayerDest = ((Ethernet)testPacket).getDestinationMACAddress(); int networkSource = ((IPv4)((Ethernet)testPacket).getPayload()). getSourceAddress(); int networkDest = ((IPv4)((Ethernet)testPacket).getPayload()). getDestinationAddress(); reset(topology); expect(topology.isAttachmentPointPort(1L, (short)1)) .andReturn(true) .anyTimes(); expect(topology.isAttachmentPointPort(2L, (short)3)) .andReturn(true) .anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)3)) .andReturn(true) .anyTimes(); replay(topology); srcDevice = deviceManager.learnEntity(Ethernet.toLong(dataLayerSource), null, networkSource, 1L, 1); IDeviceService.fcStore. put(cntx, IDeviceService.CONTEXT_SRC_DEVICE, srcDevice); if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) { dstDevice1 = deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), null, networkDest, 2L, 3); IDeviceService.fcStore.put(cntx, IDeviceService.CONTEXT_DST_DEVICE, dstDevice1); } if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) { dstDevice2 = deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), null, networkDest, 1L, 3); IDeviceService.fcStore.put(cntx, IDeviceService.CONTEXT_DST_DEVICE, dstDevice2); } verify(topology); } @Test public void testForwardMultiSwitchPath() throws Exception { learnDevices(DestDeviceToLearn.DEVICE1); Capture wc1 = new Capture(CaptureType.ALL); Capture wc2 = new Capture(CaptureType.ALL); Capture bc1 = new Capture(CaptureType.ALL); Capture bc2 = new Capture(CaptureType.ALL); Route route = new Route(1L, 2L); List nptList = new ArrayList(); nptList.add(new NodePortTuple(1L, (short)1)); nptList.add(new NodePortTuple(1L, (short)3)); nptList.add(new NodePortTuple(2L, (short)1)); nptList.add(new NodePortTuple(2L, (short)3)); route.setPath(nptList); expect(routingEngine.getRoute(1L, (short)1, 2L, (short)3)).andReturn(route).atLeastOnce(); // Expected Flow-mods OFMatch match = new OFMatch(); match.loadFromPacket(testPacketSerialized, (short) 1); OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); List actions = new ArrayList(); actions.add(action); OFFlowMod fm1 = (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.FLOW_MOD); fm1.setIdleTimeout((short)5) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFFlowMod fm2 = fm1.clone(); ((OFActionOutput)fm2.getActions().get(0)).setPort((short) 3); sw1.write(capture(wc1), capture(bc1)); expectLastCall().anyTimes(); sw2.write(capture(wc2), capture(bc2)); expectLastCall().anyTimes(); reset(topology); expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); expect(topology.isAttachmentPointPort(2L, (short)3)).andReturn(true).anyTimes(); expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); // Reset mocks, trigger the packet in, and validate results replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); verify(sw1, sw2, routingEngine); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. List msglist = wc1.getValues(); for (OFMessage m: msglist) { if (m instanceof OFFlowMod) assertEquals(fm1, m); else if (m instanceof OFPacketOut) assertEquals(packetOut, m); } OFMessage m = wc2.getValue(); assert (m instanceof OFFlowMod); assertTrue(m.equals(fm2)); } @Test public void testForwardSingleSwitchPath() throws Exception { learnDevices(DestDeviceToLearn.DEVICE2); Route route = new Route(1L, 1L); route.getPath().add(new NodePortTuple(1L, (short)1)); route.getPath().add(new NodePortTuple(1L, (short)3)); expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3)).andReturn(route).atLeastOnce(); // Expected Flow-mods OFMatch match = new OFMatch(); match.loadFromPacket(testPacketSerialized, (short) 1); OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); List actions = new ArrayList(); actions.add(action); OFFlowMod fm1 = (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.FLOW_MOD); fm1.setIdleTimeout((short)5) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH); // Record expected packet-outs/flow-mods sw1.write(fm1, cntx); sw1.write(packetOut, cntx); reset(topology); expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)3)).andReturn(true).anyTimes(); // Reset mocks, trigger the packet in, and validate results replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); verify(sw1, sw2, routingEngine); } @Test public void testFlowModDampening() throws Exception { learnDevices(DestDeviceToLearn.DEVICE2); reset(topology); expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(true).anyTimes(); expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); replay(topology); Route route = new Route(1L, 1L); route.getPath().add(new NodePortTuple(1L, (short)1)); route.getPath().add(new NodePortTuple(1L, (short)3)); expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3)).andReturn(route).atLeastOnce(); // Expected Flow-mods OFMatch match = new OFMatch(); match.loadFromPacket(testPacketSerialized, (short) 1); OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); List actions = new ArrayList(); actions.add(action); OFFlowMod fm1 = (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.FLOW_MOD); fm1.setIdleTimeout((short)5) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH); // Record expected packet-outs/flow-mods // We will inject the packet_in 3 times and expect 1 flow mod and // 3 packet outs due to flow mod dampening sw1.write(fm1, cntx); expectLastCall().once(); sw1.write(packetOut, cntx); expectLastCall().times(3); reset(topology); expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); expect(topology.isAttachmentPointPort(1L, (short)3)).andReturn(true).anyTimes(); // Reset mocks, trigger the packet in, and validate results replay(sw1, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); forwarding.receive(sw1, this.packetIn, cntx); forwarding.receive(sw1, this.packetIn, cntx); verify(sw1, routingEngine); } @Test public void testForwardNoPath() throws Exception { learnDevices(DestDeviceToLearn.NONE); // Set no destination attachment point or route // expect no Flow-mod but expect the packet to be flooded // Reset mocks, trigger the packet in, and validate results reset(topology); expect(topology.isIncomingBroadcastAllowed(1L, (short)1)).andReturn(true).anyTimes(); expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(true) .anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) .andReturn(true).anyTimes(); sw1.write(packetOutFlooded, cntx); expectLastCall().once(); replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); verify(sw1, sw2, routingEngine); } } floodlight-0.90/src/test/java/net/floodlightcontroller/virtualnetwork/0000775000175000017500000000000012041336206027062 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java0000664000175000017500000004237712041336206034750 0ustar jamespagejamespagepackage net.floodlightcontroller.virtualnetwork; import static org.easymock.EasyMock.*; import java.util.List; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFType; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.core.test.PacketFactory; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.test.MockDeviceManager; import net.floodlightcontroller.flowcache.FlowReconcileManager; import net.floodlightcontroller.flowcache.IFlowReconcileService; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.util.MACAddress; import net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter; public class VirtualNetworkFilterTest extends FloodlightTestCase { protected VirtualNetworkFilter vns; protected MockDeviceManager deviceService; protected static String guid1 = "guid1"; protected static String net1 = "net1"; protected static String gw1 = "1.1.1.1"; protected static String guid2 = "guid2"; protected static String net2 = "net2"; protected static String guid3 = "guid3"; protected static String net3 = "net3"; protected static String gw2 = "2.2.2.2"; protected static MACAddress mac1 = new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:55")); protected static MACAddress mac2 = new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:66")); protected static MACAddress mac3 = new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:77")); protected static MACAddress mac4 = new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:88")); protected static String hostPort1 = "port1"; protected static String hostPort2 = "port2"; protected static String hostPort3 = "port3"; protected static String hostPort4 = "port4"; // For testing forwarding behavior protected IOFSwitch sw1; protected FloodlightContext cntx; protected OFPacketIn mac1ToMac2PacketIn; protected IPacket mac1ToMac2PacketIntestPacket; protected byte[] mac1ToMac2PacketIntestPacketSerialized; protected OFPacketIn mac1ToMac4PacketIn; protected IPacket mac1ToMac4PacketIntestPacket; protected byte[] mac1ToMac4PacketIntestPacketSerialized; protected OFPacketIn mac1ToGwPacketIn; protected IPacket mac1ToGwPacketIntestPacket; protected byte[] mac1ToGwPacketIntestPacketSerialized; protected OFPacketIn packetInDHCPDiscoveryRequest; @Before public void setUp() throws Exception { super.setUp(); // Module loading stuff FloodlightModuleContext fmc = new FloodlightModuleContext(); RestApiServer restApi = new RestApiServer(); deviceService = new MockDeviceManager(); FlowReconcileManager frm = new FlowReconcileManager(); MockThreadPoolService tps = new MockThreadPoolService(); ITopologyService topology = createMock(ITopologyService.class); vns = new VirtualNetworkFilter(); DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); fmc.addService(IRestApiService.class, restApi); fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); fmc.addService(IDeviceService.class, deviceService); fmc.addService(IFlowReconcileService.class, frm); fmc.addService(IThreadPoolService.class, tps); fmc.addService(IEntityClassifierService.class, entityClassifier); fmc.addService(ITopologyService.class, topology); tps.init(fmc); frm.init(fmc); deviceService.init(fmc); restApi.init(fmc); getMockFloodlightProvider().init(fmc); entityClassifier.init(fmc); tps.startUp(fmc); vns.init(fmc); frm.startUp(fmc); deviceService.startUp(fmc); restApi.startUp(fmc); getMockFloodlightProvider().startUp(fmc); vns.startUp(fmc); entityClassifier.startUp(fmc); topology.addListener(deviceService); expectLastCall().times(1); replay(topology); // Mock switches //fastWilcards mocked as this constant int fastWildcards = OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS; sw1 = EasyMock.createNiceMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer)fastWildcards).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); replay(sw1); // Mock packets // Mock from MAC1 -> MAC2 mac1ToMac2PacketIntestPacket = new Ethernet() .setDestinationMACAddress(mac2.toBytes()) .setSourceMACAddress(mac1.toBytes()) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); mac1ToMac2PacketIntestPacketSerialized = mac1ToMac2PacketIntestPacket.serialize(); mac1ToMac2PacketIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(mac1ToMac2PacketIntestPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) mac1ToMac2PacketIntestPacketSerialized.length); // Mock from MAC1 -> MAC4 mac1ToMac4PacketIntestPacket = new Ethernet() .setDestinationMACAddress(mac4.toBytes()) .setSourceMACAddress(mac1.toBytes()) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); mac1ToMac4PacketIntestPacketSerialized = mac1ToMac4PacketIntestPacket.serialize(); mac1ToMac4PacketIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(mac1ToMac4PacketIntestPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) mac1ToMac4PacketIntestPacketSerialized.length); // Mock from MAC1 to gateway1 mac1ToGwPacketIntestPacket = new Ethernet() .setDestinationMACAddress("00:11:33:33:44:55") // mac shouldn't matter, can't be other host .setSourceMACAddress(mac1.toBytes()) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress(gw1) .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); mac1ToGwPacketIntestPacketSerialized = mac1ToGwPacketIntestPacket.serialize(); mac1ToGwPacketIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(mac1ToGwPacketIntestPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) mac1ToGwPacketIntestPacketSerialized.length); } @Test public void testCreateNetwork() { // Test creating a network with all parameters vns.createNetwork(guid1, net1, IPv4.toIPv4Address(gw1)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); assertTrue(vns.nameToGuid.get(net1).equals(guid1)); assertTrue(vns.guidToGateway.get(guid1).equals(IPv4.toIPv4Address(gw1))); assertTrue(vns.vNetsByGuid.get(guid1).name.equals(net1)); assertTrue(vns.vNetsByGuid.get(guid1).guid.equals(guid1)); assertTrue(vns.vNetsByGuid.get(guid1).gateway.equals(gw1)); assertTrue(vns.vNetsByGuid.get(guid1).hosts.size()==0); // Test creating network without a gateway vns.createNetwork(guid2, net2, null); assertTrue(vns.nameToGuid.get(net2).equals(guid2)); assertTrue(vns.guidToGateway.get(guid2) == null); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 1); assertTrue(vns.vNetsByGuid.get(guid2).name.equals(net2)); assertTrue(vns.vNetsByGuid.get(guid2).guid.equals(guid2)); assertTrue(vns.vNetsByGuid.get(guid2).gateway == null); assertTrue(vns.vNetsByGuid.get(guid2).hosts.size()==0); // Test creating a network that shares the gateway with net1 vns.createNetwork(guid3, net3, IPv4.toIPv4Address(gw1)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 2); assertTrue(vns.nameToGuid.get(net3).equals(guid3)); assertTrue(vns.guidToGateway.get(guid3).equals(IPv4.toIPv4Address(gw1))); assertTrue(vns.vNetsByGuid.get(guid3).name.equals(net3)); assertTrue(vns.vNetsByGuid.get(guid3).guid.equals(guid3)); assertTrue(vns.vNetsByGuid.get(guid3).gateway.equals(gw1)); assertTrue(vns.vNetsByGuid.get(guid3).hosts.size()==0); } @Test public void testModifyNetwork() { // Create some networks testCreateNetwork(); // Modify net2 to add a gateway vns.createNetwork(guid2, net2, IPv4.toIPv4Address(gw1)); assertTrue(vns.nameToGuid.get(net2).equals(guid2)); assertTrue(vns.guidToGateway.get(guid2).equals(IPv4.toIPv4Address(gw1))); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid2)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 3); // Modify net2 to change it's name vns.createNetwork(guid2, "newnet2", null); // Make sure the gateway is still there assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid2)); assertTrue(vns.vNetsByGuid.get(guid2).gateway.equals(gw1)); // make sure the new name mapping was learned assertTrue(vns.nameToGuid.get("newnet2").equals(guid2)); assertTrue(vns.vNetsByGuid.get(guid2).name.equals("newnet2")); // and the old one was deleted assertFalse(vns.nameToGuid.containsKey(net2)); } @Test public void testDeleteNetwork() { testModifyNetwork(); // Delete newnet2 vns.deleteNetwork(guid2); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 2); assertFalse(vns.nameToGuid.containsKey(net2)); assertFalse(vns.guidToGateway.containsKey(net2)); assertTrue(vns.vNetsByGuid.get(guid2)==null); } @Test public void testAddHost() { testModifyNetwork(); vns.addHost(mac1, guid1, hostPort1); assertTrue(vns.macToGuid.get(mac1).equals(guid1)); assertTrue(vns.portToMac.get(hostPort1).equals(mac1)); assertTrue(vns.vNetsByGuid.get(guid1).hosts.contains(mac1)); vns.addHost(mac2, guid1, hostPort2); assertTrue(vns.macToGuid.get(mac2).equals(guid1)); assertTrue(vns.portToMac.get(hostPort2).equals(mac2)); assertTrue(vns.vNetsByGuid.get(guid1).hosts.contains(mac2)); vns.addHost(mac3, guid3, hostPort3); vns.addHost(mac4, guid3, hostPort4); assertTrue(vns.vNetsByGuid.get(guid3).hosts.contains(mac4)); } @Test public void testDeleteHost() { testAddHost(); String host1Guid = vns.macToGuid.get(mac1); vns.deleteHost(mac1, null); assertFalse(vns.macToGuid.containsKey(mac1)); assertFalse(vns.portToMac.containsKey(hostPort1)); assertFalse(vns.vNetsByGuid.get(host1Guid).hosts.contains(mac1)); String host2Guid = vns.macToGuid.get(vns.portToMac.get(hostPort2)); vns.deleteHost(null, hostPort2); assertFalse(vns.macToGuid.containsKey(mac2)); assertFalse(vns.portToMac.containsKey(hostPort2)); assertFalse(vns.vNetsByGuid.get(host2Guid).hosts.contains(mac2)); String host3Guid = vns.macToGuid.get(mac3); vns.deleteHost(mac3, hostPort3); assertFalse(vns.macToGuid.containsKey(mac3)); assertFalse(vns.portToMac.containsKey(hostPort3)); assertFalse(vns.vNetsByGuid.get(host3Guid).hosts.contains(mac3)); } @Test public void testForwarding() { testAddHost(); // make sure mac1 can communicate with mac2 IOFMessageListener listener = getVirtualNetworkListener(); cntx = new FloodlightContext(); IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)mac1ToMac2PacketIntestPacket); Command ret = listener.receive(sw1, mac1ToMac2PacketIn, cntx); assertTrue(ret == Command.CONTINUE); // make sure mac1 can't communicate with mac4 cntx = new FloodlightContext(); IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)mac1ToMac4PacketIntestPacket); ret = listener.receive(sw1, mac1ToMac4PacketIn, cntx); assertTrue(ret == Command.STOP); } @Test public void testDefaultGateway() { testAddHost(); IOFMessageListener listener = getVirtualNetworkListener(); cntx = new FloodlightContext(); IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)mac1ToGwPacketIntestPacket); deviceService.learnEntity(((Ethernet)mac1ToGwPacketIntestPacket).getDestinationMAC().toLong(), null, IPv4.toIPv4Address(gw1), null, null); Command ret = listener.receive(sw1, mac1ToGwPacketIn, cntx); assertTrue(ret == Command.CONTINUE); } @Test public void testDhcp() { IOFMessageListener listener = getVirtualNetworkListener(); Ethernet dhcpPacket = PacketFactory.DhcpDiscoveryRequestEthernet(mac1); OFPacketIn dhcpPacketOf = PacketFactory.DhcpDiscoveryRequestOFPacketIn(mac1); cntx = new FloodlightContext(); IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, dhcpPacket); Command ret = listener.receive(sw1, dhcpPacketOf, cntx); assertTrue(ret == Command.CONTINUE); } protected IOFMessageListener getVirtualNetworkListener() { List listeners = mockFloodlightProvider.getListeners().get(OFType.PACKET_IN); return listeners.get(listeners.indexOf(vns)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/hub/0000775000175000017500000000000012041336206024540 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/hub/HubTest.java0000664000175000017500000001523012041336206026762 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.hub; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.capture; import java.util.Arrays; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.test.FloodlightTestCase; import org.easymock.Capture; import org.easymock.CaptureType; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class HubTest extends FloodlightTestCase { protected OFPacketIn packetIn; protected IPacket testPacket; protected byte[] testPacketSerialized; private MockFloodlightProvider mockFloodlightProvider; private Hub hub; @Before public void setUp() throws Exception { super.setUp(); mockFloodlightProvider = getMockFloodlightProvider(); hub = new Hub(); mockFloodlightProvider.addOFMessageListener(OFType.PACKET_IN, hub); hub.setFloodlightProvider(mockFloodlightProvider); // Build our test packet this.testPacket = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.testPacketSerialized = testPacket.serialize(); // Build the PacketIn this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) this.testPacketSerialized.length); } @Test public void testFloodNoBufferId() throws Exception { // build our expected flooded packetOut OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT)) .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testPacketSerialized); po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU() + this.testPacketSerialized.length); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); Capture wc1 = new Capture(CaptureType.ALL); Capture bc1 = new Capture(CaptureType.ALL); mockSwitch.write(capture(wc1), capture(bc1)); // Start recording the replay on the mocks replay(mockSwitch); // Get the listener and trigger the packet in IOFMessageListener listener = mockFloodlightProvider.getListeners().get( OFType.PACKET_IN).get(0); listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); // Verify the replay matched our expectations verify(mockSwitch); assertTrue(wc1.hasCaptured()); OFMessage m = wc1.getValue(); assert(m.equals(po)); } @Test public void testFloodBufferId() throws Exception { MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider(); this.packetIn.setBufferId(10); // build our expected flooded packetOut OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT)) .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setBufferId(10) .setInPort((short) 1); po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU()); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); Capture wc1 = new Capture(CaptureType.ALL); Capture bc1 = new Capture(CaptureType.ALL); mockSwitch.write(capture(wc1), capture(bc1)); // Start recording the replay on the mocks replay(mockSwitch); // Get the listener and trigger the packet in IOFMessageListener listener = mockFloodlightProvider.getListeners().get( OFType.PACKET_IN).get(0); listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); // Verify the replay matched our expectations verify(mockSwitch); assertTrue(wc1.hasCaptured()); OFMessage m = wc1.getValue(); assert(m.equals(po)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/firewall/0000775000175000017500000000000012041336206025567 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java0000664000175000017500000004670012041336206031046 0ustar jamespagejamespagepackage net.floodlightcontroller.firewall; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.TCP; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.util.MACAddress; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.OFType; import org.openflow.util.HexString; /** * Unit test for stateless firewall implemented as a Google Summer of Code project. * * @author Amer Tahir */ public class FirewallTest extends FloodlightTestCase { protected MockFloodlightProvider mockFloodlightProvider; protected FloodlightContext cntx; protected OFPacketIn packetIn; protected IOFSwitch sw; protected IPacket tcpPacket; protected IPacket broadcastARPPacket; protected IPacket ARPReplyPacket; protected IPacket broadcastIPPacket; protected IPacket tcpPacketReply; protected IPacket broadcastMalformedPacket; private Firewall firewall; public static String TestSwitch1DPID = "00:00:00:00:00:00:00:01"; @Before public void setUp() throws Exception { super.setUp(); cntx = new FloodlightContext(); mockFloodlightProvider = getMockFloodlightProvider(); firewall = new Firewall(); IStorageSourceService storageService = new MemoryStorageSource(); RestApiServer restApi = new RestApiServer(); // Mock switches long dpid = HexString.toLong(TestSwitch1DPID); sw = EasyMock.createNiceMock(IOFSwitch.class); expect(sw.getId()).andReturn(dpid).anyTimes(); expect(sw.getStringId()).andReturn(TestSwitch1DPID).anyTimes(); replay(sw); // Load the switch map Map switches = new HashMap(); switches.put(dpid, sw); mockFloodlightProvider.setSwitches(switches); FloodlightModuleContext fmc = new FloodlightModuleContext(); fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); fmc.addService(IFirewallService.class, firewall); fmc.addService(IStorageSourceService.class, storageService); fmc.addService(IRestApiService.class, restApi); try { restApi.init(fmc); } catch (FloodlightModuleException e) { e.printStackTrace(); } firewall.init(fmc); firewall.startUp(fmc); // Build our test packet this.tcpPacket = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new TCP() .setSourcePort((short) 81) .setDestinationPort((short) 80) .setPayload(new Data(new byte[] {0x01})))); // Build a broadcast ARP packet this.broadcastARPPacket = new Ethernet() .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setOpCode(ARP.OP_REQUEST) .setHardwareAddressLength((byte)6) .setProtocolAddressLength((byte)4) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) .setSenderProtocolAddress(IPv4.toIPv4Address("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:00:00:00:00:00")) .setTargetProtocolAddress(IPv4.toIPv4Address("192.168.1.2")) .setPayload(new Data(new byte[] {0x01}))); // Build a ARP packet this.ARPReplyPacket = new Ethernet() .setDestinationMACAddress("00:44:33:22:11:00") .setSourceMACAddress("00:11:22:33:44:55") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setOpCode(ARP.OP_REQUEST) .setHardwareAddressLength((byte)6) .setProtocolAddressLength((byte)4) .setSenderHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setSenderProtocolAddress(IPv4.toIPv4Address("192.168.1.2")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) .setTargetProtocolAddress(IPv4.toIPv4Address("192.168.1.1")) .setPayload(new Data(new byte[] {0x01}))); // Build a broadcast IP packet this.broadcastIPPacket = new Ethernet() .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.255") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); // Build a malformed broadcast packet this.broadcastMalformedPacket = new Ethernet() .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.tcpPacketReply = new Ethernet() .setDestinationMACAddress("00:44:33:22:11:00") .setSourceMACAddress("00:11:22:33:44:55") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.2") .setDestinationAddress("192.168.1.1") .setPayload(new TCP() .setSourcePort((short) 80) .setDestinationPort((short) 81) .setPayload(new Data(new byte[] {0x02})))); } protected void setPacketIn(IPacket packet) { byte[] serializedPacket = packet.serialize(); // Build the PacketIn this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(serializedPacket) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) serializedPacket.length); // Add the packet to the context store IFloodlightProviderService.bcStore. put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)packet); } @Test public void testNoRules() throws Exception { // enable firewall first firewall.enableFirewall(true); // simulate a packet-in event this.setPacketIn(tcpPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); assertEquals(0, firewall.rules.size()); IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); // no rules to match, so firewall should deny assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); } @Test public void testReadRulesFromStorage() throws Exception { // add 2 rules first FirewallRule rule = new FirewallRule(); rule.in_port = 2; rule.dl_src = MACAddress.valueOf("00:00:00:00:00:01").toLong(); rule.dl_dst = MACAddress.valueOf("00:00:00:00:00:02").toLong(); rule.priority = 1; rule.action = FirewallRule.FirewallAction.DENY; firewall.addRule(rule); rule = new FirewallRule(); rule.in_port = 3; rule.dl_src = MACAddress.valueOf("00:00:00:00:00:02").toLong(); rule.dl_dst = MACAddress.valueOf("00:00:00:00:00:01").toLong(); rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.tp_dst = 80; rule.priority = 2; rule.action = FirewallRule.FirewallAction.ALLOW; firewall.addRule(rule); List rules = firewall.readRulesFromStorage(); // verify rule 1 FirewallRule r = rules.get(0); assertEquals(r.in_port, 2); assertEquals(r.priority, 1); assertEquals(r.dl_src, MACAddress.valueOf("00:00:00:00:00:01").toLong()); assertEquals(r.dl_dst, MACAddress.valueOf("00:00:00:00:00:02").toLong()); assertEquals(r.action, FirewallRule.FirewallAction.DENY); // verify rule 2 r = rules.get(1); assertEquals(r.in_port, 3); assertEquals(r.priority, 2); assertEquals(r.dl_src, MACAddress.valueOf("00:00:00:00:00:02").toLong()); assertEquals(r.dl_dst, MACAddress.valueOf("00:00:00:00:00:01").toLong()); assertEquals(r.nw_proto, IPv4.PROTOCOL_TCP); assertEquals(r.tp_dst, 80); assertEquals(r.wildcard_nw_proto, false); assertEquals(r.action, FirewallRule.FirewallAction.ALLOW); } @Test public void testRuleInsertionIntoStorage() throws Exception { // add TCP rule FirewallRule rule = new FirewallRule(); rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.priority = 1; firewall.addRule(rule); List> rulesFromStorage = firewall.getStorageRules(); assertEquals(1, rulesFromStorage.size()); assertEquals(Integer.parseInt((String)rulesFromStorage.get(0).get("ruleid")), rule.ruleid); } @Test public void testRuleDeletion() throws Exception { // add TCP rule FirewallRule rule = new FirewallRule(); rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.priority = 1; firewall.addRule(rule); int rid = rule.ruleid; List> rulesFromStorage = firewall.getStorageRules(); assertEquals(1, rulesFromStorage.size()); assertEquals(Integer.parseInt((String)rulesFromStorage.get(0).get("ruleid")), rid); // delete rule firewall.deleteRule(rid); rulesFromStorage = firewall.getStorageRules(); assertEquals(0, rulesFromStorage.size()); } @Test public void testFirewallDisabled() throws Exception { // firewall isn't enabled by default // so, it shouldn't make any decision // add TCP rule FirewallRule rule = new FirewallRule(); rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.priority = 1; firewall.addRule(rule); this.setPacketIn(tcpPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); assertEquals(1, firewall.rules.size()); IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertNull(decision); } @Test public void testSimpleAllowRule() throws Exception { // enable firewall first firewall.enableFirewall(true); // add TCP rule FirewallRule rule = new FirewallRule(); rule.dl_type = Ethernet.TYPE_IPv4; rule.wildcard_dl_type = false; rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; // source is IP 192.168.1.2 rule.nw_src_prefix = IPv4.toIPv4Address("192.168.1.2"); rule.wildcard_nw_src = false; // dest is network 192.168.1.0/24 rule.nw_dst_prefix = IPv4.toIPv4Address("192.168.1.0"); rule.nw_dst_maskbits = 24; rule.wildcard_nw_dst = false; rule.priority = 1; firewall.addRule(rule); // simulate a packet-in events this.setPacketIn(tcpPacketReply); firewall.receive(sw, this.packetIn, cntx); verify(sw); IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); // clear decision IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); this.setPacketIn(tcpPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); } @Test public void testOverlappingRules() throws Exception { firewall.enableFirewall(true); // add TCP port 80 (destination only) allow rule FirewallRule rule = new FirewallRule(); rule.dl_type = Ethernet.TYPE_IPv4; rule.wildcard_dl_type = false; rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.tp_dst = 80; rule.priority = 1; firewall.addRule(rule); // add block all rule rule = new FirewallRule(); rule.action = FirewallRule.FirewallAction.DENY; rule.priority = 2; firewall.addRule(rule); assertEquals(2, firewall.rules.size()); // packet destined to TCP port 80 - should be allowed this.setPacketIn(tcpPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); // clear decision IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); // packet destined for port 81 - should be denied this.setPacketIn(tcpPacketReply); firewall.receive(sw, this.packetIn, cntx); verify(sw); decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); } @Test public void testARP() throws Exception { // enable firewall first firewall.enableFirewall(true); // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked // simulate an ARP broadcast packet-in event this.setPacketIn(broadcastARPPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); // broadcast-ARP traffic should be allowed IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction()); // clear decision IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); // simulate an ARP reply packet-in event this.setPacketIn(ARPReplyPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); // ARP reply traffic should be denied decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); } @Test public void testIPBroadcast() throws Exception { // enable firewall first firewall.enableFirewall(true); // set subnet mask for IP broadcast firewall.setSubnetMask("255.255.255.0"); // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked // simulate a packet-in event this.setPacketIn(broadcastIPPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); // broadcast traffic should be allowed IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction()); } @Test public void testMalformedIPBroadcast() throws Exception { // enable firewall first firewall.enableFirewall(true); // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked // simulate a packet-in event this.setPacketIn(broadcastMalformedPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); // malformed broadcast traffic should NOT be allowed IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); } @Test public void testLayer2Rule() throws Exception { // enable firewall first firewall.enableFirewall(true); // add L2 rule FirewallRule rule = new FirewallRule(); rule.dl_src = MACAddress.valueOf("00:44:33:22:11:00").toLong(); rule.wildcard_dl_src = false; rule.dl_dst = MACAddress.valueOf("00:11:22:33:44:55").toLong(); rule.wildcard_dl_dst = false; rule.priority = 1; firewall.addRule(rule); // add TCP deny all rule rule = new FirewallRule(); rule.nw_proto = IPv4.PROTOCOL_TCP; rule.wildcard_nw_proto = false; rule.priority = 2; rule.action = FirewallRule.FirewallAction.DENY; firewall.addRule(rule); // simulate a packet-in event this.setPacketIn(tcpPacket); firewall.receive(sw, this.packetIn, cntx); verify(sw); IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); } } floodlight-0.90/src/test/java/net/floodlightcontroller/util/0000775000175000017500000000000012041336206024737 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/util/MACAddressTest.java0000664000175000017500000000566612041336206030365 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import org.junit.Test; import static org.junit.Assert.*; /** * @author Sho Shimizu (sho.shimizu@gmail.com) */ public class MACAddressTest { @Test public void testValueOf() { MACAddress address = MACAddress.valueOf("00:01:02:03:04:05"); assertEquals(address, MACAddress.valueOf(new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05})); assertEquals("00:01:02:03:04:05", address.toString()); address = MACAddress.valueOf("FF:FE:FD:10:20:30"); assertEquals(address, MACAddress.valueOf(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFD, 0x10, 0x20, 0x30})); assertEquals("FF:FE:FD:10:20:30", address.toString()); address = MACAddress.valueOf("00:11:22:aa:bb:cc"); assertEquals(address, MACAddress.valueOf(new byte[]{0x00, 0x11, 0x22, (byte)0xaa, (byte)0xbb, (byte)0xcc})); } @Test(expected=NumberFormatException.class) public void testIllegalFormat() { MACAddress.valueOf("0T:00:01:02:03:04"); } @Test(expected=IllegalArgumentException.class) public void testLongStringFields() { MACAddress.valueOf("00:01:02:03:04:05:06"); } @Test(expected=IllegalArgumentException.class) public void testShortStringFields() { MACAddress.valueOf("00:01:02:03:04"); } @Test(expected=IllegalArgumentException.class) public void testLongByteFields() { MACAddress.valueOf(new byte[]{0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}); } @Test(expected=IllegalArgumentException.class) public void testShortByteField() { MACAddress.valueOf(new byte[]{0x01, 0x01, 0x02, 0x03, 0x04}); } // Test data is imported from net.floodlightcontroller.packet.EthernetTest @Test public void testToLong() { assertEquals( 281474976710655L, MACAddress.valueOf(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}).toLong()); assertEquals( 1103823438081L, MACAddress.valueOf(new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }).toLong()); assertEquals( 141289400074368L, MACAddress.valueOf(new byte[] { (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 }).toLong()); } @Test public void testIsBroadcast() { assertTrue(MACAddress.valueOf("FF:FF:FF:FF:FF:FF").isBroadcast()); assertFalse(MACAddress.valueOf("11:22:33:44:55:66").isBroadcast()); } @Test public void testIsMulticast() { assertTrue(MACAddress.valueOf("01:80:C2:00:00:00").isMulticast()); assertFalse(MACAddress.valueOf("FF:FF:FF:FF:FF:FF").isMulticast()); assertFalse(MACAddress.valueOf("11:22:33:44:55:66").isBroadcast()); } } floodlight-0.90/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java0000664000175000017500000002217312041336206032545 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import static org.junit.Assert.*; import java.io.IOException; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import org.jboss.netty.channel.Channel; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFStatisticsRequest; import org.openflow.protocol.statistics.OFDescriptionStatistics; import org.openflow.protocol.statistics.OFStatistics; /** * A mock implementation of IFOSwitch we use for {@link OFMessageDamper} * * We need to mock equals() and hashCode() but alas, EasyMock doesn't support * this. Sigh. And of course this happens to be the interface with the most * methods. * @author gregor * */ public class OFMessageDamperMockSwitch implements IOFSwitch { OFMessage writtenMessage; FloodlightContext writtenContext; public OFMessageDamperMockSwitch() { reset(); } /* reset this mock. I.e., clear the stored message previously written */ public void reset() { writtenMessage = null; writtenContext = null; } /* assert that a message was written to this switch and that the * written message and context matches the expected values * @param expected * @param expectedContext */ public void assertMessageWasWritten(OFMessage expected, FloodlightContext expectedContext) { assertNotNull("No OFMessage was written", writtenMessage); assertEquals(expected, writtenMessage); assertEquals(expectedContext, writtenContext); } /* * assert that no message was written */ public void assertNoMessageWritten() { assertNull("OFMessage was written but didn't expect one", writtenMessage); assertNull("There was a context but didn't expect one", writtenContext); } /* * use hashCode() and equals() from Object */ //------------------------------------------------------- // IOFSwitch: mocked methods @Override public void write(OFMessage m, FloodlightContext bc) throws IOException { assertNull("write() called but already have message", writtenMessage); assertNull("write() called but already have context", writtenContext); writtenContext = bc; writtenMessage = m; } //------------------------------------------------------- // IOFSwitch: not-implemented methods @Override public void write(List msglist, FloodlightContext bc) throws IOException { assertTrue("Unexpected method call", false); } @Override public void disconnectOutputStream() { assertTrue("Unexpected method call", false); } @Override public Channel getChannel() { assertTrue("Unexpected method call", false); return null; } @Override public void setFeaturesReply(OFFeaturesReply featuresReply) { assertTrue("Unexpected method call", false); } @Override public void setSwitchProperties(OFDescriptionStatistics description) { assertTrue("Unexpected method call", false); // TODO Auto-generated method stub } @Override public Collection getEnabledPorts() { assertTrue("Unexpected method call", false); return null; } @Override public Collection getEnabledPortNumbers() { assertTrue("Unexpected method call", false); return null; } @Override public OFPhysicalPort getPort(short portNumber) { assertTrue("Unexpected method call", false); return null; } @Override public OFPhysicalPort getPort(String portName) { assertTrue("Unexpected method call", false); return null; } @Override public void setPort(OFPhysicalPort port) { assertTrue("Unexpected method call", false); } @Override public void deletePort(short portNumber) { assertTrue("Unexpected method call", false); } @Override public void deletePort(String portName) { assertTrue("Unexpected method call", false); } @Override public Collection getPorts() { assertTrue("Unexpected method call", false); return null; } @Override public boolean portEnabled(short portName) { assertTrue("Unexpected method call", false); return false; } @Override public boolean portEnabled(String portName) { assertTrue("Unexpected method call", false); return false; } @Override public boolean portEnabled(OFPhysicalPort port) { assertTrue("Unexpected method call", false); return false; } @Override public long getId() { assertTrue("Unexpected method call", false); return 0; } @Override public String getStringId() { assertTrue("Unexpected method call", false); return null; } @Override public Map getAttributes() { assertTrue("Unexpected method call", false); return null; } @Override public Date getConnectedSince() { assertTrue("Unexpected method call", false); return null; } @Override public int getNextTransactionId() { assertTrue("Unexpected method call", false); return 0; } @Override public Future> getStatistics(OFStatisticsRequest request) throws IOException { assertTrue("Unexpected method call", false); return null; } @Override public boolean isConnected() { assertTrue("Unexpected method call", false); return false; } @Override public void setConnected(boolean connected) { assertTrue("Unexpected method call", false); } @Override public Role getRole() { assertTrue("Unexpected method call", false); return null; } @Override public boolean isActive() { assertTrue("Unexpected method call", false); return false; } @Override public void deliverStatisticsReply(OFMessage reply) { assertTrue("Unexpected method call", false); } @Override public void cancelStatisticsReply(int transactionId) { assertTrue("Unexpected method call", false); } @Override public void cancelAllStatisticsReplies() { assertTrue("Unexpected method call", false); } @Override public boolean hasAttribute(String name) { assertTrue("Unexpected method call", false); return false; } @Override public Object getAttribute(String name) { assertTrue("Unexpected method call", false); return null; } @Override public void setAttribute(String name, Object value) { assertTrue("Unexpected method call", false); } @Override public Object removeAttribute(String name) { assertTrue("Unexpected method call", false); return null; } @Override public void clearAllFlowMods() { assertTrue("Unexpected method call", false); } @Override public boolean updateBroadcastCache(Long entry, Short port) { assertTrue("Unexpected method call", false); return false; } @Override public Map getPortBroadcastHits() { assertTrue("Unexpected method call", false); return null; } @Override public void sendStatsQuery(OFStatisticsRequest request, int xid, IOFMessageListener caller) throws IOException { assertTrue("Unexpected method call", false); } @Override public void flush() { assertTrue("Unexpected method call", false); } @Override public Future getFeaturesReplyFromSwitch() throws IOException { // TODO Auto-generated method stub return null; } @Override public void deliverOFFeaturesReply(OFMessage reply) { // TODO Auto-generated method stub } @Override public void cancelFeaturesReply(int transactionId) { // TODO Auto-generated method stub } @Override public int getBuffers() { // TODO Auto-generated method stub return 0; } @Override public int getActions() { // TODO Auto-generated method stub return 0; } @Override public int getCapabilities() { // TODO Auto-generated method stub return 0; } @Override public byte getTables() { // TODO Auto-generated method stub return 0; } }floodlight-0.90/src/test/java/net/floodlightcontroller/util/OFMessageDamperTest.java0000664000175000017500000001145412041336206031411 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import static org.junit.Assert.*; import net.floodlightcontroller.core.FloodlightContext; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFEchoRequest; import org.openflow.protocol.OFHello; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.OFMessageFactory; import java.io.IOException; import java.util.EnumSet; public class OFMessageDamperTest { OFMessageFactory factory; OFMessageDamper damper; FloodlightContext cntx; OFMessageDamperMockSwitch sw1; OFMessageDamperMockSwitch sw2; OFEchoRequest echoRequst1; OFEchoRequest echoRequst1Clone; OFEchoRequest echoRequst2; OFHello hello1; OFHello hello2; @Before public void setUp() throws IOException { factory = new BasicFactory(); cntx = new FloodlightContext(); sw1 = new OFMessageDamperMockSwitch(); sw2 = new OFMessageDamperMockSwitch(); echoRequst1 = (OFEchoRequest)factory.getMessage(OFType.ECHO_REQUEST); echoRequst1.setPayload(new byte[] { 1 }); echoRequst1Clone = (OFEchoRequest) factory.getMessage(OFType.ECHO_REQUEST); echoRequst1Clone.setPayload(new byte[] { 1 }); echoRequst2 = (OFEchoRequest)factory.getMessage(OFType.ECHO_REQUEST); echoRequst2.setPayload(new byte[] { 2 }); hello1 = (OFHello)factory.getMessage(OFType.HELLO); hello1.setXid(1); hello2 = (OFHello)factory.getMessage(OFType.HELLO); hello2.setXid(2); } protected void doWrite(boolean expectWrite, OFMessageDamperMockSwitch sw, OFMessage msg, FloodlightContext cntx) throws IOException { boolean result; sw.reset(); result = damper.write(sw, msg, cntx); if (expectWrite) { assertEquals(true, result); sw.assertMessageWasWritten(msg, cntx); } else { assertEquals(false, result); sw.assertNoMessageWritten(); } } @Test public void testOneMessageType() throws IOException, InterruptedException { int timeout = 50; int sleepTime = 60; damper = new OFMessageDamper(100, EnumSet.of(OFType.ECHO_REQUEST), timeout); // echo requests should be dampened doWrite(true, sw1, echoRequst1, cntx); doWrite(false, sw1, echoRequst1, cntx); doWrite(false, sw1, echoRequst1Clone, cntx); doWrite(true, sw1, echoRequst2, cntx); doWrite(false, sw1, echoRequst2, cntx); // we don't dampen hellos. All should succeed doWrite(true, sw1, hello1, cntx); doWrite(true, sw1, hello1, cntx); doWrite(true, sw1, hello1, cntx); // echo request should also be dampened on sw2 doWrite(true, sw2, echoRequst1, cntx); doWrite(false, sw2, echoRequst1, cntx); doWrite(true, sw2, echoRequst2, cntx); Thread.sleep(sleepTime); doWrite(true, sw1, echoRequst1, cntx); doWrite(true, sw2, echoRequst1, cntx); } @Test public void testTwoMessageTypes() throws IOException, InterruptedException { int timeout = 50; int sleepTime = 60; damper = new OFMessageDamper(100, EnumSet.of(OFType.ECHO_REQUEST, OFType.HELLO), timeout); // echo requests should be dampened doWrite(true, sw1, echoRequst1, cntx); doWrite(false, sw1, echoRequst1, cntx); doWrite(false, sw1, echoRequst1Clone, cntx); doWrite(true, sw1, echoRequst2, cntx); doWrite(false, sw1, echoRequst2, cntx); // hello should be dampened as well doWrite(true, sw1, hello1, cntx); doWrite(false, sw1, hello1, cntx); doWrite(false, sw1, hello1, cntx); doWrite(true, sw1, hello2, cntx); doWrite(false, sw1, hello2, cntx); doWrite(false, sw1, hello2, cntx); // echo request should also be dampened on sw2 doWrite(true, sw2, echoRequst1, cntx); doWrite(false, sw2, echoRequst1, cntx); doWrite(true, sw2, echoRequst2, cntx); Thread.sleep(sleepTime); doWrite(true, sw1, echoRequst1, cntx); doWrite(true, sw2, echoRequst1, cntx); doWrite(true, sw1, hello1, cntx); doWrite(true, sw1, hello2, cntx); } } floodlight-0.90/src/test/java/net/floodlightcontroller/util/TimedCacheTest.java0000664000175000017500000000474612041336206030443 0ustar jamespagejamespagepackage net.floodlightcontroller.util; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class TimedCacheTest { public static class CacheEntry { public int key; public CacheEntry(int key) { this.key = key; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + key; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CacheEntry other = (CacheEntry) obj; if (key != other.key) return false; return true; } } protected TimedCache cache; @Before public void setUp() { // } @Test public void testCaching() throws InterruptedException { int timeout = 50; int timeToSleep = 60; cache = new TimedCache(100, timeout); CacheEntry e1a = new CacheEntry(1); CacheEntry e1b = new CacheEntry(1); CacheEntry e1c = new CacheEntry(1); CacheEntry e2 = new CacheEntry(2); assertEquals(false, cache.update(e1a)); assertEquals(true, cache.update(e1a)); assertEquals(true, cache.update(e1b)); assertEquals(true, cache.update(e1c)); assertEquals(false, cache.update(e2)); assertEquals(true, cache.update(e2)); Thread.sleep(timeToSleep); assertEquals(false, cache.update(e1a)); assertEquals(false, cache.update(e2)); } @Test public void testCapacity() throws InterruptedException { int timeout = 5000; cache = new TimedCache(2, timeout); // Testing the capacity is tricky since the capacity can be // exceeded for short amounts of time, so we try to flood the cache // to make sure the first entry is expired CacheEntry e1 = new CacheEntry(1); for (int i=0; i < 100; i++) { CacheEntry e = new CacheEntry(i); cache.update(e); } // entry 1 should have been expired due to capacity limits assertEquals(false, cache.update(e1)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/test/0000775000175000017500000000000012041336206024741 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java0000664000175000017500000000665312041336206031345 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.test; import junit.framework.TestCase; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.packet.Ethernet; import org.junit.Test; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFType; /** * This class gets a handle on the application context which is used to * retrieve Spring beans from during tests * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class FloodlightTestCase extends TestCase { protected MockFloodlightProvider mockFloodlightProvider; public MockFloodlightProvider getMockFloodlightProvider() { return mockFloodlightProvider; } public void setMockFloodlightProvider(MockFloodlightProvider mockFloodlightProvider) { this.mockFloodlightProvider = mockFloodlightProvider; } public FloodlightContext parseAndAnnotate(OFMessage m, IDevice srcDevice, IDevice dstDevice) { FloodlightContext bc = new FloodlightContext(); return parseAndAnnotate(bc, m, srcDevice, dstDevice); } public FloodlightContext parseAndAnnotate(OFMessage m) { return parseAndAnnotate(m, null, null); } public FloodlightContext parseAndAnnotate(FloodlightContext bc, OFMessage m, IDevice srcDevice, IDevice dstDevice) { if (OFType.PACKET_IN.equals(m.getType())) { OFPacketIn pi = (OFPacketIn)m; Ethernet eth = new Ethernet(); eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); IFloodlightProviderService.bcStore.put(bc, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, eth); } if (srcDevice != null) { IDeviceService.fcStore.put(bc, IDeviceService.CONTEXT_SRC_DEVICE, srcDevice); } if (dstDevice != null) { IDeviceService.fcStore.put(bc, IDeviceService.CONTEXT_DST_DEVICE, dstDevice); } return bc; } @Override public void setUp() throws Exception { mockFloodlightProvider = new MockFloodlightProvider(); } @Test public void testSanity() throws Exception { assertTrue(true); } } floodlight-0.90/src/test/java/net/floodlightcontroller/learningswitch/0000775000175000017500000000000012041336206027003 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java0000664000175000017500000002454112041336206033435 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.learningswitch; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightTestModuleLoader; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.test.FloodlightTestCase; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class LearningSwitchTest extends FloodlightTestCase { protected OFPacketIn packetIn; protected IPacket testPacket; protected byte[] testPacketSerialized; protected IPacket broadcastPacket; protected byte[] broadcastPacketSerialized; protected IPacket testPacketReply; protected byte[] testPacketReplySerialized; private LearningSwitch learningSwitch; @Before public void setUp() throws Exception { super.setUp(); FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader(); Collection> mods = new ArrayList>(); mods.add(LearningSwitch.class); fml.setupModules(mods, null); learningSwitch = (LearningSwitch) fml.getModuleByName(LearningSwitch.class); mockFloodlightProvider = (MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class); // Build our test packet this.testPacket = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.2") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.testPacketSerialized = testPacket.serialize(); // Build a broadcast packet this.broadcastPacket = new Ethernet() .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") .setSourceMACAddress("00:44:33:22:11:00") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.255.255") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); this.broadcastPacketSerialized = broadcastPacket.serialize(); this.testPacketReply = new Ethernet() .setDestinationMACAddress("00:44:33:22:11:00") .setSourceMACAddress("00:11:22:33:44:55") .setVlanID((short) 42) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.2") .setDestinationAddress("192.168.1.1") .setPayload(new UDP() .setSourcePort((short) 5001) .setDestinationPort((short) 5000) .setPayload(new Data(new byte[] {0x02})))); this.testPacketReplySerialized = testPacketReply.serialize(); // Build the PacketIn this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(this.testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) this.testPacketSerialized.length); } @Test public void testFlood() throws Exception { // build our expected flooded packetOut OFPacketOut po = new OFPacketOut() .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setBufferId(-1) .setInPort((short)1) .setPacketData(this.testPacketSerialized); po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU() + this.testPacketSerialized.length); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77").anyTimes(); mockSwitch.write(po, null); // Start recording the replay on the mocks replay(mockSwitch); // Get the listener and trigger the packet in IOFMessageListener listener = mockFloodlightProvider.getListeners().get( OFType.PACKET_IN).get(0); // Make sure it's the right listener listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); // Verify the replay matched our expectations short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue(); verify(mockSwitch); // Verify the MAC table inside the switch assertEquals(1, result); } @Test public void testFlowMod() throws Exception { // tweak the test packet in since we need a bufferId this.packetIn.setBufferId(50); // build expected flow mods OFMessage fm1 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD)) .setActions(Arrays.asList(new OFAction[] { new OFActionOutput().setPort((short) 2).setMaxLength((short) -1)})) .setBufferId(50) .setCommand(OFFlowMod.OFPFC_ADD) .setIdleTimeout((short) 5) .setMatch(new OFMatch() .loadFromPacket(testPacketSerialized, (short) 1) .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_TOS)) .setOutPort(OFPort.OFPP_NONE.getValue()) .setCookie(1L << 52) .setPriority((short) 100) .setFlags((short)(1 << 0)) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFMessage fm2 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD)) .setActions(Arrays.asList(new OFAction[] { new OFActionOutput().setPort((short) 1).setMaxLength((short) -1)})) .setBufferId(-1) .setCommand(OFFlowMod.OFPFC_ADD) .setIdleTimeout((short) 5) .setMatch(new OFMatch() .loadFromPacket(testPacketReplySerialized, (short) 2) .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_TOS)) .setOutPort(OFPort.OFPP_NONE.getValue()) .setCookie(1L << 52) .setPriority((short) 100) .setFlags((short)(1 << 0)) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); expect(mockSwitch.getId()).andReturn(1L).anyTimes(); expect(mockSwitch.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer) (OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS)); mockSwitch.write(fm1, null); mockSwitch.write(fm2, null); // Start recording the replay on the mocks replay(mockSwitch); // Populate the MAC table learningSwitch.addToPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55")), (short) 42, (short) 2); // Get the listener and trigger the packet in IOFMessageListener listener = mockFloodlightProvider.getListeners().get( OFType.PACKET_IN).get(0); listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); // Verify the replay matched our expectations short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue(); verify(mockSwitch); // Verify the MAC table inside the switch assertEquals(1, result); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/0000775000175000017500000000000012041336206024712 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/core/internal/0000775000175000017500000000000012041336206026526 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java0000664000175000017500000014517312041336206032367 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.internal; import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.FloodlightProvider; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFMessageFilterManagerService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.OFMessageFilterManager; import net.floodlightcontroller.core.internal.Controller.IUpdate; import net.floodlightcontroller.core.internal.Controller.SwitchUpdate; import net.floodlightcontroller.core.internal.Controller.SwitchUpdateType; import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.counter.CounterStore; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.perfmon.PktInProcessingTime; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.easymock.Capture; import org.easymock.EasyMock; import org.jboss.netty.channel.Channel; import org.junit.Test; import org.openflow.protocol.OFError; import org.openflow.protocol.OFError.OFBadRequestCode; import org.openflow.protocol.OFError.OFErrorType; import org.openflow.protocol.OFFeaturesReply; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPhysicalPort; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFPortStatus; import org.openflow.protocol.OFStatisticsReply; import org.openflow.protocol.OFType; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.OFPortStatus.OFPortReason; import org.openflow.protocol.OFVendor; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.statistics.OFFlowStatisticsReply; import org.openflow.protocol.statistics.OFStatistics; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.util.HexString; import org.openflow.vendor.nicira.OFNiciraVendorData; import org.openflow.vendor.nicira.OFRoleReplyVendorData; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class ControllerTest extends FloodlightTestCase { private Controller controller; private MockThreadPoolService tp; @Override public void setUp() throws Exception { super.setUp(); FloodlightModuleContext fmc = new FloodlightModuleContext(); FloodlightProvider cm = new FloodlightProvider(); controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class); fmc.addService(IFloodlightProviderService.class, controller); MemoryStorageSource memstorage = new MemoryStorageSource(); fmc.addService(IStorageSourceService.class, memstorage); RestApiServer restApi = new RestApiServer(); fmc.addService(IRestApiService.class, restApi); CounterStore cs = new CounterStore(); fmc.addService(ICounterStoreService.class, cs); PktInProcessingTime ppt = new PktInProcessingTime(); fmc.addService(IPktInProcessingTimeService.class, ppt); tp = new MockThreadPoolService(); fmc.addService(IThreadPoolService.class, tp); ppt.init(fmc); restApi.init(fmc); memstorage.init(fmc); cm.init(fmc); tp.init(fmc); ppt.startUp(fmc); restApi.startUp(fmc); memstorage.startUp(fmc); cm.startUp(fmc); tp.startUp(fmc); } public Controller getController() { return controller; } protected OFStatisticsReply getStatisticsReply(int transactionId, int count, boolean moreReplies) { OFStatisticsReply sr = new OFStatisticsReply(); sr.setXid(transactionId); sr.setStatisticType(OFStatisticsType.FLOW); List statistics = new ArrayList(); for (int i = 0; i < count; ++i) { statistics.add(new OFFlowStatisticsReply()); } sr.setStatistics(statistics); if (moreReplies) sr.setFlags((short) 1); return sr; } /* Set the mock expectations for sw when sw is passed to addSwitch */ protected void setupSwitchForAddSwitch(IOFSwitch sw, long dpid) { String dpidString = HexString.toHexString(dpid); expect(sw.getId()).andReturn(dpid).anyTimes(); expect(sw.getStringId()).andReturn(dpidString).anyTimes(); expect(sw.getConnectedSince()).andReturn(new Date()); Channel channel = createMock(Channel.class); expect(sw.getChannel()).andReturn(channel); expect(channel.getRemoteAddress()).andReturn(null); expect(sw.getCapabilities()).andReturn(0).anyTimes(); expect(sw.getBuffers()).andReturn(0).anyTimes(); expect(sw.getTables()).andReturn((byte)0).anyTimes(); expect(sw.getActions()).andReturn(0).anyTimes(); expect(sw.getPorts()).andReturn(new ArrayList()).anyTimes(); } /** * Run the controller's main loop so that updates are processed */ protected class ControllerRunThread extends Thread { public void run() { controller.openFlowPort = 0; // Don't listen controller.run(); } } /** * Verify that a listener that throws an exception halts further * execution, and verify that the Commands STOP and CONTINUE are honored. * @throws Exception */ @Test public void testHandleMessages() throws Exception { Controller controller = getController(); controller.removeOFMessageListeners(OFType.PACKET_IN); IOFSwitch sw = createMock(IOFSwitch.class); expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); // Build our test packet IPacket testPacket = new Ethernet() .setSourceMACAddress("00:44:33:22:11:00") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); byte[] testPacketSerialized = testPacket.serialize(); // Build the PacketIn OFPacketIn pi = ((OFPacketIn) new BasicFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testPacketSerialized.length); IOFMessageListener test1 = createMock(IOFMessageListener.class); expect(test1.getName()).andReturn("test1").anyTimes(); expect(test1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(test1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andThrow(new RuntimeException("This is NOT an error! We are testing exception catching.")); IOFMessageListener test2 = createMock(IOFMessageListener.class); expect(test2.getName()).andReturn("test2").anyTimes(); expect(test2.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); expect(test2.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes(); // expect no calls to test2.receive() since test1.receive() threw an exception replay(test1, test2, sw); controller.addOFMessageListener(OFType.PACKET_IN, test1); controller.addOFMessageListener(OFType.PACKET_IN, test2); try { controller.handleMessage(sw, pi, null); } catch (RuntimeException e) { assertEquals(e.getMessage().startsWith("This is NOT an error!"), true); } verify(test1, test2, sw); // verify STOP works reset(test1, test2, sw); expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andReturn(Command.STOP); //expect(test1.getId()).andReturn(0).anyTimes(); expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); replay(test1, test2, sw); controller.handleMessage(sw, pi, null); verify(test1, test2, sw); } public class FutureFetcher implements Runnable { public E value; public Future future; public FutureFetcher(Future future) { this.future = future; } @Override public void run() { try { value = future.get(); } catch (Exception e) { throw new RuntimeException(e); } } /** * @return the value */ public E getValue() { return value; } /** * @return the future */ public Future getFuture() { return future; } } /** * * @throws Exception */ @Test public void testOFStatisticsFuture() throws Exception { // Test for a single stats reply IOFSwitch sw = createMock(IOFSwitch.class); sw.cancelStatisticsReply(1); OFStatisticsFuture sf = new OFStatisticsFuture(tp, sw, 1); replay(sw); List stats; FutureFetcher> ff = new FutureFetcher>(sf); Thread t = new Thread(ff); t.start(); sf.deliverFuture(sw, getStatisticsReply(1, 10, false)); t.join(); stats = ff.getValue(); verify(sw); assertEquals(10, stats.size()); // Test multiple stats replies reset(sw); sw.cancelStatisticsReply(1); sf = new OFStatisticsFuture(tp, sw, 1); replay(sw); ff = new FutureFetcher>(sf); t = new Thread(ff); t.start(); sf.deliverFuture(sw, getStatisticsReply(1, 10, true)); sf.deliverFuture(sw, getStatisticsReply(1, 5, false)); t.join(); stats = sf.get(); verify(sw); assertEquals(15, stats.size()); // Test cancellation reset(sw); sw.cancelStatisticsReply(1); sf = new OFStatisticsFuture(tp, sw, 1); replay(sw); ff = new FutureFetcher>(sf); t = new Thread(ff); t.start(); sf.cancel(true); t.join(); stats = sf.get(); verify(sw); assertEquals(0, stats.size()); // Test self timeout reset(sw); sw.cancelStatisticsReply(1); sf = new OFStatisticsFuture(tp, sw, 1, 75, TimeUnit.MILLISECONDS); replay(sw); ff = new FutureFetcher>(sf); t = new Thread(ff); t.start(); t.join(2000); stats = sf.get(); verify(sw); assertEquals(0, stats.size()); } @Test public void testMessageFilterManager() throws Exception { class MyOFMessageFilterManager extends OFMessageFilterManager { public MyOFMessageFilterManager(int timer_interval) { super(); TIMER_INTERVAL = timer_interval; } } FloodlightModuleContext fmCntx = new FloodlightModuleContext(); MockFloodlightProvider mfp = new MockFloodlightProvider(); OFMessageFilterManager mfm = new MyOFMessageFilterManager(100); MockThreadPoolService mtp = new MockThreadPoolService(); fmCntx.addService(IOFMessageFilterManagerService.class, mfm); fmCntx.addService(IFloodlightProviderService.class, mfp); fmCntx.addService(IThreadPoolService.class, mtp); String sid = null; mfm.init(fmCntx); mfm.startUp(fmCntx); ConcurrentHashMap filter; int i; //Adding the filter works -- adds up to the maximum filter size. for(i=mfm.getMaxFilterSize(); i > 0; --i) { filter = new ConcurrentHashMap(); filter.put("mac", String.format("00:11:22:33:44:%d%d", i,i)); sid = mfm.setupFilter(null, filter, 60); assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize() - i +1); } // Add one more to see if you can't filter = new ConcurrentHashMap(); filter.put("mac", "mac2"); mfm.setupFilter(null, filter, 10*1000); assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize()); // Deleting the filter works. mfm.setupFilter(sid, null, -1); assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize()-1); // Creating mock switch to which we will send packet out and IOFSwitch sw = createMock(IOFSwitch.class); expect(sw.getId()).andReturn(new Long(0)); // Mock Packet-in IPacket testPacket = new Ethernet() .setSourceMACAddress("00:44:33:22:11:00") .setDestinationMACAddress("00:11:22:33:44:55") .setEtherType(Ethernet.TYPE_ARP) .setPayload( new ARP() .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) 6) .setProtocolAddressLength((byte) 4) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); byte[] testPacketSerialized = testPacket.serialize(); // Build the PacketIn OFPacketIn pi = ((OFPacketIn) new BasicFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testPacketSerialized.length); // Mock Packet-out OFPacketOut packetOut = (OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); packetOut.setBufferId(pi.getBufferId()) .setInPort(pi.getInPort()); List poactions = new ArrayList(); poactions.add(new OFActionOutput(OFPort.OFPP_TABLE.getValue(), (short) 0)); packetOut.setActions(poactions) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testPacketSerialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+packetOut.getActionsLength()+testPacketSerialized.length); FloodlightContext cntx = new FloodlightContext(); IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet) testPacket); // Let's check the listeners. List lm; // Check to see if all the listeners are active. lm = mfp.getListeners().get(OFType.PACKET_OUT); assertTrue(lm.size() == 1); assertTrue(lm.get(0).equals(mfm)); lm = mfp.getListeners().get(OFType.FLOW_MOD); assertTrue(lm.size() == 1); assertTrue(lm.get(0).equals(mfm)); lm = mfp.getListeners().get(OFType.PACKET_IN); assertTrue(lm.size() == 1); assertTrue(lm.get(0).equals(mfm)); HashSet matchedFilters; // Send a packet in and check if it matches a filter. matchedFilters = mfm.getMatchedFilters(pi, cntx); assertTrue(matchedFilters.size() == 1); // Send a packet out and check if it matches a filter matchedFilters = mfm.getMatchedFilters(packetOut, cntx); assertTrue(matchedFilters.size() == 1); // Wait for all filters to be timed out. Thread.sleep(150); assertEquals(0, mfm.getNumberOfFilters()); } @Test public void testAddSwitch() throws Exception { controller.activeSwitches = new ConcurrentHashMap(); //OFSwitchImpl oldsw = createMock(OFSwitchImpl.class); OFSwitchImpl oldsw = new OFSwitchImpl(); OFFeaturesReply featuresReply = new OFFeaturesReply(); featuresReply.setDatapathId(0L); featuresReply.setPorts(new ArrayList()); oldsw.setFeaturesReply(featuresReply); //expect(oldsw.getId()).andReturn(0L).anyTimes(); //expect(oldsw.asyncRemoveSwitchLock()).andReturn(rwlock.writeLock()).anyTimes(); //oldsw.setConnected(false); //expect(oldsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); Channel channel = createNiceMock(Channel.class); //expect(oldsw.getChannel()).andReturn(channel); oldsw.setChannel(channel); expect(channel.close()).andReturn(null); IOFSwitch newsw = createMock(IOFSwitch.class); expect(newsw.getId()).andReturn(0L).anyTimes(); expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); expect(newsw.getConnectedSince()).andReturn(new Date()); Channel channel2 = createMock(Channel.class); expect(newsw.getChannel()).andReturn(channel2); expect(channel2.getRemoteAddress()).andReturn(null); expect(newsw.getPorts()).andReturn(new ArrayList()); expect(newsw.getCapabilities()).andReturn(0).anyTimes(); expect(newsw.getBuffers()).andReturn(0).anyTimes(); expect(newsw.getTables()).andReturn((byte)0).anyTimes(); expect(newsw.getActions()).andReturn(0).anyTimes(); controller.activeSwitches.put(0L, oldsw); replay(newsw, channel, channel2); controller.addSwitch(newsw); verify(newsw, channel, channel2); } @Test public void testUpdateQueue() throws Exception { class DummySwitchListener implements IOFSwitchListener { public int nAdded; public int nRemoved; public int nPortChanged; public DummySwitchListener() { nAdded = 0; nRemoved = 0; nPortChanged = 0; } public synchronized void addedSwitch(IOFSwitch sw) { nAdded++; notifyAll(); } public synchronized void removedSwitch(IOFSwitch sw) { nRemoved++; notifyAll(); } public String getName() { return "dummy"; } @Override public void switchPortChanged(Long switchId) { nPortChanged++; notifyAll(); } } DummySwitchListener switchListener = new DummySwitchListener(); IOFSwitch sw = createMock(IOFSwitch.class); ControllerRunThread t = new ControllerRunThread(); t.start(); controller.addOFSwitchListener(switchListener); synchronized(switchListener) { controller.updates.put(controller.new SwitchUpdate(sw, Controller.SwitchUpdateType.ADDED)); switchListener.wait(500); assertTrue("IOFSwitchListener.addedSwitch() was not called", switchListener.nAdded == 1); controller.updates.put(controller.new SwitchUpdate(sw, Controller.SwitchUpdateType.REMOVED)); switchListener.wait(500); assertTrue("IOFSwitchListener.removedSwitch() was not called", switchListener.nRemoved == 1); controller.updates.put(controller.new SwitchUpdate(sw, Controller.SwitchUpdateType.PORTCHANGED)); switchListener.wait(500); assertTrue("IOFSwitchListener.switchPortChanged() was not called", switchListener.nPortChanged == 1); } } private Map getFakeControllerIPRow(String id, String controllerId, String type, int number, String discoveredIP ) { HashMap row = new HashMap(); row.put(Controller.CONTROLLER_INTERFACE_ID, id); row.put(Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId); row.put(Controller.CONTROLLER_INTERFACE_TYPE, type); row.put(Controller.CONTROLLER_INTERFACE_NUMBER, number); row.put(Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP); return row; } /** * Test notifications for controller node IP changes. This requires * synchronization between the main test thread and another thread * that runs Controller's main loop and takes / handles updates. We * synchronize with wait(timeout) / notifyAll(). We check for the * expected condition after the wait returns. However, if wait returns * due to the timeout (or due to spurious awaking) and the check fails we * might just not have waited long enough. Using a long enough timeout * mitigates this but we cannot get rid of the fundamental "issue". * * @throws Exception */ @Test public void testControllerNodeIPChanges() throws Exception { class DummyHAListener implements IHAListener { public Map curControllerNodeIPs; public Map addedControllerNodeIPs; public Map removedControllerNodeIPs; public int nCalled; public DummyHAListener() { this.nCalled = 0; } @Override public void roleChanged(Role oldRole, Role newRole) { // ignore } @Override public synchronized void controllerNodeIPsChanged( Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { this.curControllerNodeIPs = curControllerNodeIPs; this.addedControllerNodeIPs = addedControllerNodeIPs; this.removedControllerNodeIPs = removedControllerNodeIPs; this.nCalled++; notifyAll(); } public void do_assert(int nCalled, Map curControllerNodeIPs, Map addedControllerNodeIPs, Map removedControllerNodeIPs) { assertEquals("nCalled is not as expected", nCalled, this.nCalled); assertEquals("curControllerNodeIPs is not as expected", curControllerNodeIPs, this.curControllerNodeIPs); assertEquals("addedControllerNodeIPs is not as expected", addedControllerNodeIPs, this.addedControllerNodeIPs); assertEquals("removedControllerNodeIPs is not as expected", removedControllerNodeIPs, this.removedControllerNodeIPs); } } long waitTimeout = 250; // ms DummyHAListener listener = new DummyHAListener(); HashMap expectedCurMap = new HashMap(); HashMap expectedAddedMap = new HashMap(); HashMap expectedRemovedMap = new HashMap(); controller.addHAListener(listener); ControllerRunThread t = new ControllerRunThread(); t.start(); synchronized(listener) { // Insert a first entry controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1")); expectedCurMap.clear(); expectedAddedMap.clear(); expectedRemovedMap.clear(); expectedCurMap.put("c1", "1.1.1.1"); expectedAddedMap.put("c1", "1.1.1.1"); listener.wait(waitTimeout); listener.do_assert(1, expectedCurMap, expectedAddedMap, expectedRemovedMap); // Add an interface that we want to ignore. controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2")); listener.wait(waitTimeout); // TODO: do a different check. This call will have to wait for the timeout assertTrue("controllerNodeIPsChanged() should not have been called here", listener.nCalled == 1); // Add another entry controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2")); expectedCurMap.clear(); expectedAddedMap.clear(); expectedRemovedMap.clear(); expectedCurMap.put("c1", "1.1.1.1"); expectedCurMap.put("c2", "2.2.2.2"); expectedAddedMap.put("c2", "2.2.2.2"); listener.wait(waitTimeout); listener.do_assert(2, expectedCurMap, expectedAddedMap, expectedRemovedMap); // Update an entry controller.storageSource.updateRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3")); expectedCurMap.clear(); expectedAddedMap.clear(); expectedRemovedMap.clear(); expectedCurMap.put("c1", "1.1.1.1"); expectedCurMap.put("c2", "2.2.2.3"); expectedAddedMap.put("c2", "2.2.2.3"); expectedRemovedMap.put("c2", "2.2.2.2"); listener.wait(waitTimeout); listener.do_assert(3, expectedCurMap, expectedAddedMap, expectedRemovedMap); // Delete an entry controller.storageSource.deleteRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3"); expectedCurMap.clear(); expectedAddedMap.clear(); expectedRemovedMap.clear(); expectedCurMap.put("c1", "1.1.1.1"); expectedRemovedMap.put("c2", "2.2.2.3"); listener.wait(waitTimeout); listener.do_assert(4, expectedCurMap, expectedAddedMap, expectedRemovedMap); } } @Test public void testGetControllerNodeIPs() { HashMap expectedCurMap = new HashMap(); controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1")); controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2")); controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2")); expectedCurMap.put("c1", "1.1.1.1"); expectedCurMap.put("c2", "2.2.2.2"); assertEquals("expectedControllerNodeIPs is not as expected", expectedCurMap, controller.getControllerNodeIPs()); } @Test public void testSetRoleNull() { try { controller.setRole(null); fail("Should have thrown an Exception"); } catch (NullPointerException e) { //exptected } } @Test public void testSetRole() { controller.connectedSwitches.add(new OFSwitchImpl()); RoleChanger roleChanger = createMock(RoleChanger.class); roleChanger.submitRequest(controller.connectedSwitches, Role.SLAVE); controller.roleChanger = roleChanger; assertEquals("Check that update queue is empty", 0, controller.updates.size()); replay(roleChanger); controller.setRole(Role.SLAVE); verify(roleChanger); Controller.IUpdate upd = controller.updates.poll(); assertNotNull("Check that update queue has an update", upd); assertTrue("Check that update is HARoleUpdate", upd instanceof Controller.HARoleUpdate); Controller.HARoleUpdate roleUpd = (Controller.HARoleUpdate)upd; assertSame(null, roleUpd.oldRole); assertSame(Role.SLAVE, roleUpd.newRole); } @Test public void testCheckSwitchReady() { OFChannelState state = new OFChannelState(); Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); chdlr.sw = createMock(OFSwitchImpl.class); // Wrong current state // Should not go to READY state.hsState = OFChannelState.HandshakeState.HELLO; state.hasDescription = true; state.hasGetConfigReply = true; replay(chdlr.sw); // nothing called on sw chdlr.checkSwitchReady(); verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.HELLO, state.hsState); reset(chdlr.sw); // Have only config reply state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = false; state.hasGetConfigReply = true; replay(chdlr.sw); chdlr.checkSwitchReady(); verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState); assertTrue(controller.connectedSwitches.isEmpty()); assertTrue(controller.activeSwitches.isEmpty()); reset(chdlr.sw); // Have only desc reply state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = true; state.hasGetConfigReply = false; replay(chdlr.sw); chdlr.checkSwitchReady(); verify(chdlr.sw); assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState); assertTrue(controller.connectedSwitches.isEmpty()); assertTrue(controller.activeSwitches.isEmpty()); reset(chdlr.sw); ////////////////////////////////////////// // Finally, everything is right. Should advance to READY ////////////////////////////////////////// controller.roleChanger = createMock(RoleChanger.class); state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; state.hasDescription = true; state.hasGetConfigReply = true; // Role support disabled. Switch should be promoted to active switch // list. setupSwitchForAddSwitch(chdlr.sw, 0L); chdlr.sw.clearAllFlowMods(); replay(controller.roleChanger, chdlr.sw); chdlr.checkSwitchReady(); verify(controller.roleChanger, chdlr.sw); assertSame(OFChannelState.HandshakeState.READY, state.hsState); assertSame(chdlr.sw, controller.activeSwitches.get(0L)); assertTrue(controller.connectedSwitches.contains(chdlr.sw)); assertTrue(state.firstRoleReplyReceived); reset(chdlr.sw); reset(controller.roleChanger); controller.connectedSwitches.clear(); controller.activeSwitches.clear(); // Role support enabled. state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY; controller.role = Role.MASTER; Capture> swListCapture = new Capture>(); controller.roleChanger.submitRequest(capture(swListCapture), same(Role.MASTER)); replay(controller.roleChanger, chdlr.sw); chdlr.checkSwitchReady(); verify(controller.roleChanger, chdlr.sw); assertSame(OFChannelState.HandshakeState.READY, state.hsState); assertTrue(controller.activeSwitches.isEmpty()); assertTrue(controller.connectedSwitches.contains(chdlr.sw)); assertTrue(state.firstRoleReplyReceived); Collection swList = swListCapture.getValue(); assertEquals(1, swList.size()); assertTrue("swList must contain this switch", swList.contains(chdlr.sw)); } @Test public void testChannelDisconnected() throws Exception { OFChannelState state = new OFChannelState(); state.hsState = OFChannelState.HandshakeState.READY; Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); chdlr.sw = createMock(OFSwitchImpl.class); // Switch is active expect(chdlr.sw.getId()).andReturn(0L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:00") .anyTimes(); chdlr.sw.cancelAllStatisticsReplies(); chdlr.sw.setConnected(false); expect(chdlr.sw.isConnected()).andReturn(true); controller.connectedSwitches.add(chdlr.sw); controller.activeSwitches.put(0L, chdlr.sw); replay(chdlr.sw); chdlr.channelDisconnected(null, null); verify(chdlr.sw); // Switch is connected but not active reset(chdlr.sw); expect(chdlr.sw.getId()).andReturn(0L).anyTimes(); chdlr.sw.setConnected(false); replay(chdlr.sw); chdlr.channelDisconnected(null, null); verify(chdlr.sw); // Not in ready state state.hsState = HandshakeState.START; reset(chdlr.sw); replay(chdlr.sw); chdlr.channelDisconnected(null, null); verify(chdlr.sw); // Switch is null state.hsState = HandshakeState.READY; chdlr.sw = null; chdlr.channelDisconnected(null, null); } /* @Test public void testRoleChangeForSerialFailoverSwitch() throws Exception { OFSwitchImpl newsw = createMock(OFSwitchImpl.class); expect(newsw.getId()).andReturn(0L).anyTimes(); expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); Channel channel2 = createMock(Channel.class); expect(newsw.getChannel()).andReturn(channel2); // newsw.role is null because the switch does not support // role request messages expect(newsw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); // switch is connected controller.connectedSwitches.add(newsw); // the switch should get disconnected when role is changed to SLAVE expect(channel2.close()).andReturn(null); replay(newsw, channel2); controller.setRole(Role.SLAVE); verify(newsw, channel2); } */ @Test public void testRoleNotSupportedError() throws Exception { int xid = 424242; OFChannelState state = new OFChannelState(); state.hsState = HandshakeState.READY; Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); chdlr.sw = createMock(OFSwitchImpl.class); Channel ch = createMock(Channel.class); // the error returned when role request message is not supported by sw OFError msg = new OFError(); msg.setType(OFType.ERROR); msg.setXid(xid); msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST); msg.setErrorCode(OFBadRequestCode.OFPBRC_BAD_VENDOR); // the switch connection should get disconnected when the controller is // in SLAVE mode and the switch does not support role-request messages state.firstRoleReplyReceived = false; controller.role = Role.SLAVE; expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true); chdlr.sw.deliverRoleRequestNotSupported(xid); expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes(); expect(ch.close()).andReturn(null); replay(ch, chdlr.sw); chdlr.processOFMessage(msg); verify(ch, chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); reset(ch, chdlr.sw); // a different error message - should also reject role request msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST); msg.setErrorCode(OFBadRequestCode.OFPBRC_EPERM); state.firstRoleReplyReceived = false; controller.role = Role.SLAVE; expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true); chdlr.sw.deliverRoleRequestNotSupported(xid); expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes(); expect(ch.close()).andReturn(null); replay(ch, chdlr.sw); chdlr.processOFMessage(msg); verify(ch, chdlr.sw); assertTrue("state.firstRoleReplyReceived must be True even with EPERM", state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); reset(ch, chdlr.sw); // We are MASTER, the switch should be added to the list of active // switches. state.firstRoleReplyReceived = false; controller.role = Role.MASTER; expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true); chdlr.sw.deliverRoleRequestNotSupported(xid); setupSwitchForAddSwitch(chdlr.sw, 0L); chdlr.sw.clearAllFlowMods(); replay(ch, chdlr.sw); chdlr.processOFMessage(msg); verify(ch, chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(0L)); reset(ch, chdlr.sw); } @Test public void testVendorMessageUnknown() throws Exception { // Check behavior with an unknown vendor id OFChannelState state = new OFChannelState(); state.hsState = HandshakeState.READY; Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); OFVendor msg = new OFVendor(); msg.setVendor(0); chdlr.processOFMessage(msg); } // Helper function. protected Controller.OFChannelHandler getChannelHandlerForRoleReplyTest() { OFChannelState state = new OFChannelState(); state.hsState = HandshakeState.READY; Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state); chdlr.sw = createMock(OFSwitchImpl.class); return chdlr; } // Helper function protected OFVendor getRoleReplyMsgForRoleReplyTest(int xid, int nicira_role) { OFVendor msg = new OFVendor(); msg.setXid(xid); msg.setVendor(OFNiciraVendorData.NX_VENDOR_ID); OFRoleReplyVendorData roleReplyVendorData = new OFRoleReplyVendorData(OFRoleReplyVendorData.NXT_ROLE_REPLY); msg.setVendorData(roleReplyVendorData); roleReplyVendorData.setRole(nicira_role); return msg; } /** invalid role in role reply */ @Test public void testNiciraRoleReplyInvalidRole() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); Channel ch = createMock(Channel.class); expect(chdlr.sw.getChannel()).andReturn(ch); expect(ch.close()).andReturn(null); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 232323); replay(chdlr.sw, ch); chdlr.processOFMessage(msg); verify(chdlr.sw, ch); } /** First role reply message received: transition from slave to master */ @Test public void testNiciraRoleReplySlave2MasterFristTime() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.sw.clearAllFlowMods(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); } /** Not first role reply message received: transition from slave to master */ @Test public void testNiciraRoleReplySlave2MasterNotFristTime() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.state.firstRoleReplyReceived = true; // Flow table shouldn't be wipe replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); } /** transition from slave to equal */ @Test public void testNiciraRoleReplySlave2Equal() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_OTHER); chdlr.sw.deliverRoleReply(xid, Role.EQUAL); expect(chdlr.sw.isActive()).andReturn(true); setupSwitchForAddSwitch(chdlr.sw, 1L); chdlr.sw.clearAllFlowMods(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); }; @Test /** Slave2Slave transition ==> no change */ public void testNiciraRoleReplySlave2Slave() throws Exception{ int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_SLAVE); chdlr.sw.deliverRoleReply(xid, Role.SLAVE); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); expect(chdlr.sw.isActive()).andReturn(false); // don't add switch to activeSwitches ==> slave2slave chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); } @Test /** Equal2Master transition ==> no change */ public void testNiciraRoleReplyEqual2Master() throws Exception{ int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_MASTER); chdlr.sw.deliverRoleReply(xid, Role.MASTER); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); expect(chdlr.sw.isActive()).andReturn(true); controller.activeSwitches.put(1L, chdlr.sw); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertSame("activeSwitches must contain this switch", chdlr.sw, controller.activeSwitches.get(1L)); } @Test public void testNiciraRoleReplyMaster2Slave() throws Exception { int xid = 424242; Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest(); OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, OFRoleReplyVendorData.NX_ROLE_SLAVE); chdlr.sw.deliverRoleReply(xid, Role.SLAVE); expect(chdlr.sw.getId()).andReturn(1L).anyTimes(); expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01") .anyTimes(); controller.activeSwitches.put(1L, chdlr.sw); expect(chdlr.sw.isActive()).andReturn(false); expect(chdlr.sw.isConnected()).andReturn(true); chdlr.sw.cancelAllStatisticsReplies(); chdlr.state.firstRoleReplyReceived = false; replay(chdlr.sw); chdlr.processOFMessage(msg); verify(chdlr.sw); assertTrue("state.firstRoleReplyReceived must be true", chdlr.state.firstRoleReplyReceived); assertTrue("activeSwitches must be empty", controller.activeSwitches.isEmpty()); } /** * Tests that you can't remove a switch from the active * switch list. * @throws Exception */ @Test public void testRemoveActiveSwitch() { IOFSwitch sw = EasyMock.createNiceMock(IOFSwitch.class); boolean exceptionThrown = false; expect(sw.getId()).andReturn(1L).anyTimes(); replay(sw); getController().activeSwitches.put(sw.getId(), sw); try { getController().getSwitches().remove(1L); } catch (UnsupportedOperationException e) { exceptionThrown = true; } assertTrue(exceptionThrown); verify(sw); } public void verifyPortChangedUpdateInQueue(IOFSwitch sw) throws Exception { assertEquals(1, controller.updates.size()); IUpdate update = controller.updates.take(); assertEquals(true, update instanceof SwitchUpdate); SwitchUpdate swUpdate = (SwitchUpdate)update; assertEquals(sw, swUpdate.sw); assertEquals(SwitchUpdateType.PORTCHANGED, swUpdate.switchUpdateType); } /* * Test handlePortStatus() * TODO: test correct updateStorage behavior! */ @Test public void testHandlePortStatus() throws Exception { IOFSwitch sw = createMock(IOFSwitch.class); OFPhysicalPort port = new OFPhysicalPort(); port.setName("myPortName1"); port.setPortNumber((short)42); OFPortStatus ofps = new OFPortStatus(); ofps.setDesc(port); ofps.setReason((byte)OFPortReason.OFPPR_ADD.ordinal()); sw.setPort(port); expectLastCall().once(); replay(sw); controller.handlePortStatusMessage(sw, ofps, false); verify(sw); verifyPortChangedUpdateInQueue(sw); reset(sw); ofps.setReason((byte)OFPortReason.OFPPR_MODIFY.ordinal()); sw.setPort(port); expectLastCall().once(); replay(sw); controller.handlePortStatusMessage(sw, ofps, false); verify(sw); verifyPortChangedUpdateInQueue(sw); reset(sw); ofps.setReason((byte)OFPortReason.OFPPR_DELETE.ordinal()); sw.deletePort(port.getPortNumber()); expectLastCall().once(); replay(sw); controller.handlePortStatusMessage(sw, ofps, false); verify(sw); verifyPortChangedUpdateInQueue(sw); reset(sw); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java0000664000175000017500000002337012041336206032546 0ustar jamespagejamespagepackage net.floodlightcontroller.core.internal; import static org.easymock.EasyMock.*; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.List; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.internal.OFSwitchImpl.PendingRoleRequestEntry; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.test.FloodlightTestCase; import org.easymock.Capture; import org.jboss.netty.channel.Channel; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFType; import org.openflow.protocol.OFVendor; import org.openflow.protocol.vendor.OFVendorData; import org.openflow.vendor.nicira.OFNiciraVendorData; import org.openflow.vendor.nicira.OFRoleRequestVendorData; import org.openflow.vendor.nicira.OFRoleVendorData; public class OFSwitchImplTest extends FloodlightTestCase { protected OFSwitchImpl sw; @Before public void setUp() throws Exception { sw = new OFSwitchImpl(); Channel ch = createMock(Channel.class); SocketAddress sa = new InetSocketAddress(42); expect(ch.getRemoteAddress()).andReturn(sa).anyTimes(); sw.setChannel(ch); MockFloodlightProvider floodlightProvider = new MockFloodlightProvider(); sw.setFloodlightProvider(floodlightProvider); } public void doSendNxRoleRequest(Role role, int nx_role) throws Exception { long cookie = System.nanoTime(); // verify that the correct OFMessage is sent Capture> msgCapture = new Capture>(); expect(sw.channel.write(capture(msgCapture))).andReturn(null); replay(sw.channel); int xid = sw.sendNxRoleRequest(role, cookie); verify(sw.channel); List msgList = msgCapture.getValue(); assertEquals(1, msgList.size()); OFMessage msg = msgList.get(0); assertEquals("Transaction Ids must match", xid, msg.getXid()); assertTrue("Message must be an OFVendor type", msg instanceof OFVendor); assertEquals(OFType.VENDOR, msg.getType()); OFVendor vendorMsg = (OFVendor)msg; assertEquals("Vendor message must be vendor Nicira", OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor()); OFVendorData vendorData = vendorMsg.getVendorData(); assertTrue("Vendor Data must be an OFRoleRequestVendorData", vendorData instanceof OFRoleRequestVendorData); OFRoleRequestVendorData roleRequest = (OFRoleRequestVendorData)vendorData; assertEquals(nx_role, roleRequest.getRole()); // Now verify that we've added the pending request correctly // to the pending queue assertEquals(1, sw.pendingRoleRequests.size()); PendingRoleRequestEntry pendingRoleRequest = sw.pendingRoleRequests.poll(); assertEquals(msg.getXid(), pendingRoleRequest.xid); assertEquals(role, pendingRoleRequest.role); assertEquals(cookie, pendingRoleRequest.cookie); reset(sw.channel); } @Test public void testSendNxRoleRequest() throws Exception { doSendNxRoleRequest(Role.MASTER, OFRoleVendorData.NX_ROLE_MASTER); doSendNxRoleRequest(Role.SLAVE, OFRoleVendorData.NX_ROLE_SLAVE); doSendNxRoleRequest(Role.EQUAL, OFRoleVendorData.NX_ROLE_OTHER); } @Test public void testDeliverRoleReplyOk() { // test normal case PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleReply(pending.xid, pending.role); verify(sw.channel); assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(pending.role, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleReplyOkRepeated() { // test normal case. Not the first role reply PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleReply(pending.xid, pending.role); verify(sw.channel); assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(pending.role, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleReplyNonePending() { // nothing pending expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleReply(1, Role.MASTER); verify(sw.channel); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleReplyWrongXid() { // wrong xid received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleReply(pending.xid+1, pending.role); verify(sw.channel); assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleReplyWrongRole() { // correct xid but incorrect role received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleReply(pending.xid, Role.SLAVE); verify(sw.channel); assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testCheckFirstPendingRoleRequestXid() { PendingRoleRequestEntry pending = new PendingRoleRequestEntry( 54321, Role.MASTER, 232323); replay(sw.channel); // we don't expect any invocations sw.pendingRoleRequests.add(pending); assertEquals(true, sw.checkFirstPendingRoleRequestXid(54321)); assertEquals(false, sw.checkFirstPendingRoleRequestXid(0)); sw.pendingRoleRequests.clear(); assertEquals(false, sw.checkFirstPendingRoleRequestXid(54321)); verify(sw.channel); } @Test public void testCheckFirstPendingRoleRequestCookie() { PendingRoleRequestEntry pending = new PendingRoleRequestEntry( 54321, Role.MASTER, 232323); replay(sw.channel); // we don't expect any invocations sw.pendingRoleRequests.add(pending); assertEquals(true, sw.checkFirstPendingRoleRequestCookie(232323)); assertEquals(false, sw.checkFirstPendingRoleRequestCookie(0)); sw.pendingRoleRequests.clear(); assertEquals(false, sw.checkFirstPendingRoleRequestCookie(232323)); verify(sw.channel); } @Test public void testDeliverRoleRequestNotSupported () { // normal case. xid is pending PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.role = Role.SLAVE; sw.pendingRoleRequests.add(pending); replay(sw.channel); sw.deliverRoleRequestNotSupported(pending.xid); verify(sw.channel); assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)); assertEquals(null, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleRequestNotSupportedNonePending() { // nothing pending sw.role = Role.SLAVE; expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleRequestNotSupported(1); verify(sw.channel); assertEquals(null, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); } @Test public void testDeliverRoleRequestNotSupportedWrongXid() { // wrong xid received PendingRoleRequestEntry pending = new PendingRoleRequestEntry( (int)System.currentTimeMillis(), // arbitrary xid Role.MASTER, System.nanoTime() // arbitrary cookie ); sw.role = Role.SLAVE; sw.pendingRoleRequests.add(pending); expect(sw.channel.close()).andReturn(null); replay(sw.channel); sw.deliverRoleRequestNotSupported(pending.xid+1); verify(sw.channel); assertEquals(null, sw.role); assertEquals(0, sw.pendingRoleRequests.size()); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java0000664000175000017500000002141612041336206032426 0ustar jamespagejamespagepackage net.floodlightcontroller.core.internal; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.*; import java.io.IOException; import java.util.Collection; import java.util.LinkedList; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.internal.RoleChanger.RoleChangeTask; import org.easymock.EasyMock; import org.jboss.netty.channel.Channel; import org.junit.Before; import org.junit.Test; public class RoleChangerTest { public RoleChanger roleChanger; @Before public void setUp() throws Exception { roleChanger = new RoleChanger(); } /** * Send a role request for SLAVE to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestSlaveNotSupported() { LinkedList switches = new LinkedList(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1, channel1); roleChanger.sendRoleRequest(switches, Role.SLAVE, 123456); verify(sw1, channel1); // sendRoleRequest needs to remove the switch from the list since // it closed its connection assertTrue(switches.isEmpty()); } /** * Send a role request for MASTER to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestMasterNotSupported() { LinkedList switches = new LinkedList(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertEquals(1, switches.size()); } /** * Send a role request a switch that supports it and one that * hasn't had a role request send to it yet */ @Test public void testSendRoleRequestErrorHandling () throws Exception { LinkedList switches = new LinkedList(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)) .andThrow(new IOException()).once(); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertTrue(switches.isEmpty()); } /** * Check error handling * hasn't had a role request send to it yet */ @Test public void testSendRoleRequestSupported() throws Exception { LinkedList switches = new LinkedList(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once(); switches.add(sw1); // a switch for which we don't have SUPPORTS_NX_ROLE yet OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw2.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(null); expect(sw2.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once(); switches.add(sw2); replay(sw1, sw2); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1, sw2); assertEquals(2, switches.size()); } @Test public void testVerifyRoleReplyReceived() { LinkedList switches = new LinkedList(); // Add a switch that has received a role reply OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); expect(sw1.checkFirstPendingRoleRequestCookie(123456)) .andReturn(false).once(); switches.add(sw1); // Add a switch that has not yet received a role reply OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class); expect(sw2.checkFirstPendingRoleRequestCookie(123456)) .andReturn(true).once(); Channel channel2 = createMock(Channel.class); expect(sw2.getChannel()).andReturn(channel2); expect(channel2.close()).andReturn(null); switches.add(sw2); replay(sw1, sw2); roleChanger.verifyRoleReplyReceived(switches, 123456); verify(sw1, sw2); assertEquals(2, switches.size()); } @Test public void testRoleChangeTask() { @SuppressWarnings("unchecked") Collection switches = EasyMock.createMock(Collection.class); long now = System.nanoTime(); long dt1 = 10 * 1000*1000*1000L; long dt2 = 20 * 1000*1000*1000L; long dt3 = 15 * 1000*1000*1000L; RoleChangeTask t1 = new RoleChangeTask(switches, null, now+dt1); RoleChangeTask t2 = new RoleChangeTask(switches, null, now+dt2); RoleChangeTask t3 = new RoleChangeTask(switches, null, now+dt3); // FIXME: cannot test comparison against self. grrr //assertTrue( t1.compareTo(t1) <= 0 ); assertTrue( t1.compareTo(t2) < 0 ); assertTrue( t1.compareTo(t3) < 0 ); assertTrue( t2.compareTo(t1) > 0 ); //assertTrue( t2.compareTo(t2) <= 0 ); assertTrue( t2.compareTo(t3) > 0 ); } @Test public void testSubmitRequest() throws Exception { LinkedList switches = new LinkedList(); roleChanger.timeout = 500*1000*1000; // 500 ms // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createStrictMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(EasyMock.same(Role.MASTER), EasyMock.anyLong())) .andReturn(1); expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(EasyMock.same(Role.SLAVE), EasyMock.anyLong())) .andReturn(1); // The following calls happen for timeout handling: expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong())) .andReturn(false); expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong())) .andReturn(false); switches.add(sw1); replay(sw1); roleChanger.submitRequest(switches, Role.MASTER); roleChanger.submitRequest(switches, Role.SLAVE); // Wait until role request has been sent. // TODO: need to get rid of this sleep somehow Thread.sleep(100); // Now there should be exactly one timeout task pending assertEquals(2, roleChanger.pendingTasks.size()); // Make sure it's indeed a timeout task assertSame(RoleChanger.RoleChangeTask.Type.TIMEOUT, roleChanger.pendingTasks.peek().type); // Check that RoleChanger indeed made a copy of switches collection assertNotSame(switches, roleChanger.pendingTasks.peek().switches); // Wait until the timeout triggers // TODO: get rid of this sleep too. Thread.sleep(500); assertEquals(0, roleChanger.pendingTasks.size()); verify(sw1); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/module/0000775000175000017500000000000012041336206026177 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java0000664000175000017500000001644512041336206034304 0ustar jamespagejamespagepackage net.floodlightcontroller.core.module; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.module.FloodlightModuleLoader; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.counter.NullCounterStore; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.test.MockDeviceManager; import net.floodlightcontroller.perfmon.NullPktInProcessingTime; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.topology.TopologyManager; public class FloodlightTestModuleLoader extends FloodlightModuleLoader { protected static Logger log = LoggerFactory.getLogger(FloodlightTestModuleLoader.class); // List of default modules to use unless specified otherwise public static final Class DEFAULT_STORAGE_SOURCE = MemoryStorageSource.class; public static final Class DEFAULT_FLOODLIGHT_PRPOVIDER = MockFloodlightProvider.class; public static final Class DEFAULT_TOPOLOGY_PROVIDER = TopologyManager.class; public static final Class DEFAULT_DEVICE_SERVICE = MockDeviceManager.class; public static final Class DEFAULT_COUNTER_STORE = NullCounterStore.class; public static final Class DEFAULT_THREADPOOL = MockThreadPoolService.class; public static final Class DEFAULT_ENTITY_CLASSIFIER = DefaultEntityClassifier.class; public static final Class DEFAULT_PERFMON = NullPktInProcessingTime.class; protected static final Collection> DEFAULT_MODULE_LIST; static { DEFAULT_MODULE_LIST = new ArrayList>(); DEFAULT_MODULE_LIST.add(DEFAULT_DEVICE_SERVICE); DEFAULT_MODULE_LIST.add(DEFAULT_FLOODLIGHT_PRPOVIDER); DEFAULT_MODULE_LIST.add(DEFAULT_STORAGE_SOURCE); DEFAULT_MODULE_LIST.add(DEFAULT_TOPOLOGY_PROVIDER); DEFAULT_MODULE_LIST.add(DEFAULT_COUNTER_STORE); DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL); DEFAULT_MODULE_LIST.add(DEFAULT_ENTITY_CLASSIFIER); DEFAULT_MODULE_LIST.add(DEFAULT_PERFMON); } protected IFloodlightModuleContext fmc; /** * Adds default modules to the list of modules to load. This is done * in order to avoid the module loader throwing errors about duplicate * modules and neither one is specified by the user. * @param userModules The list of user specified modules to add to. */ protected void addDefaultModules(Collection> userModules) { Collection> defaultModules = new ArrayList>(DEFAULT_MODULE_LIST.size()); defaultModules.addAll(DEFAULT_MODULE_LIST); Iterator> modIter = userModules.iterator(); while (modIter.hasNext()) { Class userMod = modIter.next(); Iterator> dmIter = defaultModules.iterator(); while (dmIter.hasNext()) { Class dmMod = dmIter.next(); Collection> userModServs; Collection> dmModServs; try { dmModServs = dmMod.newInstance().getModuleServices(); userModServs = userMod.newInstance().getModuleServices(); } catch (InstantiationException e) { log.error(e.getMessage()); break; } catch (IllegalAccessException e) { log.error(e.getMessage()); break; } // If either of these are null continue as they have no services if (dmModServs == null || userModServs == null) continue; // If the user supplied modules has a service // that is in the default module list we remove // the default module from the list. boolean shouldBreak = false; Iterator> userModServsIter = userModServs.iterator(); while (userModServsIter.hasNext()) { Class userModServIntf = userModServsIter.next(); Iterator> dmModsServsIter = dmModServs.iterator(); while (dmModsServsIter.hasNext()) { Class dmModServIntf = dmModsServsIter.next(); if (dmModServIntf.getCanonicalName().equals( userModServIntf.getCanonicalName())) { logger.debug("Removing default module {} because it was " + "overriden by an explicitly specified module", dmModServIntf.getCanonicalName()); dmIter.remove(); shouldBreak = true; break; } } if (shouldBreak) break; } if (shouldBreak) break; } } // Append the remaining default modules to the user specified ones. // This avoids the module loader throwing duplicate module errors. userModules.addAll(defaultModules); log.debug("Using module set " + userModules.toString()); } /** * Sets up all modules and their dependencies. * @param modules The list of modules that the user wants to load. * @param mockedServices The list of services that will be mocked. Any * module that provides this service will not be loaded. */ public void setupModules(Collection> modules, Collection mockedServices) { addDefaultModules(modules); Collection modulesAsString = new ArrayList(); for (Class m : modules) { modulesAsString.add(m.getCanonicalName()); } try { fmc = loadModulesFromList(modulesAsString, null, mockedServices); } catch (FloodlightModuleException e) { log.error(e.getMessage()); } } /** * Gets the inited/started instance of a module from the context. * @param ifl The name if the module to get, i.e. "LearningSwitch.class". * @return The inited/started instance of the module. */ public IFloodlightModule getModuleByName(Class ifl) { Collection modules = fmc.getAllModules(); for (IFloodlightModule m : modules) { if (ifl.getCanonicalName().equals(m.getClass().getCanonicalName())) { return m; } } return null; } /** * Gets an inited/started instance of a service from the context. * @param ifs The name of the service to get, i.e. "ITopologyService.class". * @return The inited/started instance of the service from teh context. */ public IFloodlightService getModuleByService(Class ifs) { Collection modules = fmc.getAllModules(); for (IFloodlightModule m : modules) { Collection> mServs = m.getModuleServices(); if (mServs == null) continue; for (Class mServClass : mServs) { if (mServClass.getCanonicalName().equals(ifs.getCanonicalName())) { assert(m instanceof IFloodlightService); return (IFloodlightService)m; } } } return null; } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/util/0000775000175000017500000000000012041336206025667 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java0000664000175000017500000001230012041336206032761 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.junit.Test; import org.openflow.protocol.OFType; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.test.FloodlightTestCase; public class MessageDispatcherTest extends FloodlightTestCase { IOFMessageListener createLMock(String name) { IOFMessageListener mock = createNiceMock(IOFMessageListener.class); expect(mock.getName()).andReturn(name).anyTimes(); return mock; } void addPrereqs(IOFMessageListener mock, String... deps) { for (String dep : deps) { expect(mock.isCallbackOrderingPrereq(OFType.PACKET_IN, dep)).andReturn(true).anyTimes(); } } void testOrdering(ArrayList inputListeners) { ListenerDispatcher ld = new ListenerDispatcher(); for (IOFMessageListener l : inputListeners) { ld.addListener(OFType.PACKET_IN, l); } for (IOFMessageListener l : inputListeners) { verify(l); } List result = ld.getOrderedListeners(); System.out.print("Ordering: "); for (IOFMessageListener l : result) { System.out.print(l.getName()); System.out.print(","); } System.out.print("\n"); for (int ind_i = 0; ind_i < result.size(); ind_i++) { IOFMessageListener i = result.get(ind_i); for (int ind_j = ind_i+1; ind_j < result.size(); ind_j++) { IOFMessageListener j = result.get(ind_j); boolean orderwrong = (i.isCallbackOrderingPrereq(OFType.PACKET_IN, j.getName()) || j.isCallbackOrderingPostreq(OFType.PACKET_IN, i.getName())); assertFalse("Invalid order: " + ind_i + " (" + i.getName() + ") " + ind_j + " (" + j.getName() + ") ", orderwrong); } } } void randomTestOrdering(ArrayList mocks) { Random rand = new Random(0); ArrayList random = new ArrayList(); random.addAll(mocks); for (int i = 0; i < 20; i++) { for (int j = 0; j < random.size(); j++) { int ind = rand.nextInt(mocks.size()-1); IOFMessageListener tmp = random.get(j); random.set(j, random.get(ind)); random.set(ind, tmp); } testOrdering(random); } } @Test public void testCallbackOrderingSimple() throws Exception { ArrayList mocks = new ArrayList(); for (int i = 0; i < 10; i++) { mocks.add(createLMock(""+i)); } for (int i = 1; i < 10; i++) { addPrereqs(mocks.get(i), ""+(i-1)); } for (IOFMessageListener l : mocks) { replay(l); } randomTestOrdering(mocks); } @Test public void testCallbackOrderingPartial() throws Exception { ArrayList mocks = new ArrayList(); for (int i = 0; i < 10; i++) { mocks.add(createLMock(""+i)); } for (int i = 1; i < 5; i++) { addPrereqs(mocks.get(i), ""+(i-1)); } for (int i = 6; i < 10; i++) { addPrereqs(mocks.get(i), ""+(i-1)); } for (IOFMessageListener l : mocks) { replay(l); } randomTestOrdering(mocks); } @Test public void testCallbackOrderingPartial2() throws Exception { ArrayList mocks = new ArrayList(); for (int i = 0; i < 10; i++) { mocks.add(createLMock(""+i)); } for (int i = 2; i < 5; i++) { addPrereqs(mocks.get(i), ""+(i-1)); } for (int i = 6; i < 9; i++) { addPrereqs(mocks.get(i), ""+(i-1)); } for (IOFMessageListener l : mocks) { replay(l); } randomTestOrdering(mocks); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java0000664000175000017500000002535512041336206032171 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import net.floodlightcontroller.test.FloodlightTestCase; public class SingletonTaskTest extends FloodlightTestCase { public int ran = 0; public int finished = 0; public long time = 0; @Before public void setup() { ran = 0; finished = 0; time = 0; } @Test public void testBasic() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { ran += 1; } }); st1.reschedule(0, null); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); assertEquals("Check that task ran", 1, ran); } @Test public void testDelay() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { ran += 1; time = System.nanoTime(); } }); long start = System.nanoTime(); st1.reschedule(10, TimeUnit.MILLISECONDS); assertFalse("Check that task hasn't run yet", ran > 0); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); assertEquals("Check that task ran", 1, ran); assertTrue("Check that time passed appropriately", (time - start) >= TimeUnit.NANOSECONDS.convert(10, TimeUnit.MILLISECONDS)); } @Test public void testReschedule() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); final Object tc = this; SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { synchronized (tc) { ran += 1; } time = System.nanoTime(); } }); long start = System.nanoTime(); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); st1.reschedule(20, TimeUnit.MILLISECONDS); Thread.sleep(5); assertFalse("Check that task hasn't run yet", ran > 0); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); assertEquals("Check that task ran only once", 1, ran); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) >= TimeUnit.NANOSECONDS.convert(55, TimeUnit.MILLISECONDS)); } @Test public void testConcurrentAddDelay() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); final Object tc = this; SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { synchronized (tc) { ran += 1; } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (tc) { finished += 1; time = System.nanoTime(); } } }); long start = System.nanoTime(); st1.reschedule(5, TimeUnit.MILLISECONDS); Thread.sleep(20); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); st1.reschedule(75, TimeUnit.MILLISECONDS); assertTrue("Check task running state true", st1.context.taskRunning); assertTrue("Check task should run state true", st1.context.taskShouldRun); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); Thread.sleep(150); assertTrue("Check task running state false", !st1.context.taskRunning); assertTrue("Check task should run state false", !st1.context.taskShouldRun); assertEquals("Check that task ran exactly twice", 2, ran); assertEquals("Check that task finished exactly twice", 2, finished); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) >= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS)); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) <= TimeUnit.NANOSECONDS.convert(160, TimeUnit.MILLISECONDS)); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); } @Test public void testConcurrentAddDelay2() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); final Object tc = this; SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { synchronized (tc) { ran += 1; } try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (tc) { finished += 1; time = System.nanoTime(); } } }); long start = System.nanoTime(); st1.reschedule(5, TimeUnit.MILLISECONDS); Thread.sleep(20); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); st1.reschedule(25, TimeUnit.MILLISECONDS); assertTrue("Check task running state true", st1.context.taskRunning); assertTrue("Check task should run state true", st1.context.taskShouldRun); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); Thread.sleep(150); assertTrue("Check task running state false", !st1.context.taskRunning); assertTrue("Check task should run state false", !st1.context.taskShouldRun); assertEquals("Check that task ran exactly twice", 2, ran); assertEquals("Check that task finished exactly twice", 2, finished); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) >= TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS)); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) <= TimeUnit.NANOSECONDS.convert(125, TimeUnit.MILLISECONDS)); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); } @Test public void testConcurrentAddNoDelay() throws InterruptedException { ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); final Object tc = this; SingletonTask st1 = new SingletonTask(ses, new Runnable() { @Override public void run() { synchronized (tc) { ran += 1; } try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (tc) { finished += 1; time = System.nanoTime(); } } }); long start = System.nanoTime(); st1.reschedule(0, null); Thread.sleep(20); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); st1.reschedule(0, null); assertTrue("Check task running state true", st1.context.taskRunning); assertTrue("Check task should run state true", st1.context.taskShouldRun); assertEquals("Check that task started", 1, ran); assertEquals("Check that task not finished", 0, finished); Thread.sleep(150); assertTrue("Check task running state false", !st1.context.taskRunning); assertTrue("Check task should run state false", !st1.context.taskShouldRun); assertEquals("Check that task ran exactly twice", 2, ran); assertEquals("Check that task finished exactly twice", 2, finished); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) >= TimeUnit.NANOSECONDS.convert(90, TimeUnit.MILLISECONDS)); assertTrue("Check that time passed appropriately: " + (time - start), (time - start) <= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS)); ses.shutdown(); ses.awaitTermination(5, TimeUnit.SECONDS); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java0000664000175000017500000000263012041336206031245 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.util; import junit.framework.TestCase; import net.floodlightcontroller.test.FloodlightTestCase; public class AppCookieTest extends FloodlightTestCase { public void testAppCookie(){ int appID = 12; int user = 12345; long cookie = AppCookie.makeCookie(appID, user); TestCase.assertEquals(appID, AppCookie.extractApp(cookie)); TestCase.assertEquals(user, AppCookie.extractUser(cookie)); // now ensure that we don't exceed our size cookie = AppCookie.makeCookie(appID + 0x10000, user); TestCase.assertEquals(appID, AppCookie.extractApp(cookie)); TestCase.assertEquals(user, AppCookie.extractUser(cookie)); } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/test/0000775000175000017500000000000012041336206025671 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/core/test/MockScheduledExecutor.java0000664000175000017500000001611712041336206032773 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.test; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Delayed; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class MockScheduledExecutor implements ScheduledExecutorService { ScheduledExecutorService ses = null; public static class MockFuture implements Future,ScheduledFuture{ T result; ExecutionException e; /** * @param result */ public MockFuture(T result) { super(); this.result = result; } /** * @param result */ public MockFuture(ExecutionException e) { super(); this.e = e; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public T get() throws InterruptedException, ExecutionException { if (e != null) throw e; return result; } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (e != null) throw e; return result; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return true; } @Override public long getDelay(TimeUnit arg0) { return 0; } @Override public int compareTo(Delayed arg0) { return 0; } } @Override public boolean awaitTermination(long arg0, TimeUnit arg1) throws InterruptedException { return false; } @Override public List> invokeAll(Collection> arg0) throws InterruptedException { List> rlist = new ArrayList>(); for (Callable arg : arg0) { try { rlist.add(new MockFuture(arg.call())); } catch (Exception e) { rlist.add(new MockFuture(new ExecutionException(e))); } } return rlist; } @Override public List> invokeAll( Collection> arg0, long arg1, TimeUnit arg2) throws InterruptedException { return this.invokeAll(arg0); } @Override public T invokeAny(Collection> arg0) throws InterruptedException, ExecutionException { for (Callable arg : arg0) { try { return arg.call(); } catch (Exception e) { } } throw new ExecutionException(new Exception("no task completed successfully")); } @Override public T invokeAny(Collection> arg0, long arg1, TimeUnit arg2) throws InterruptedException, ExecutionException, TimeoutException { return invokeAny(arg0); } @Override public boolean isShutdown() { if (ses != null) return ses.isShutdown(); return false; } @Override public boolean isTerminated() { if (ses != null) return ses.isTerminated(); return false; } @Override public void shutdown() { if (ses != null) ses.shutdown(); } @Override public List shutdownNow() { if (ses != null) return ses.shutdownNow(); return null; } @Override public Future submit(Callable arg0) { try { return new MockFuture(arg0.call()); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public Future submit(Runnable arg0) { try { arg0.run(); return new MockFuture(null); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public Future submit(Runnable arg0, T arg1) { try { arg0.run(); return new MockFuture((T)null); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public void execute(Runnable arg0) { arg0.run(); } @Override public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { if (ses == null) ses = Executors.newScheduledThreadPool(1); try { return ses.schedule(command, delay, unit); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { if (ses == null) ses = Executors.newScheduledThreadPool(1); try { return ses.schedule(callable, delay, unit); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { if (ses == null) ses = Executors.newScheduledThreadPool(1); try { return ses.scheduleAtFixedRate(command, initialDelay, period, unit); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } @Override public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { if (ses == null) ses = Executors.newScheduledThreadPool(1); try { return ses.scheduleWithFixedDelay(command, initialDelay, delay, unit); } catch (Exception e) { return new MockFuture(new ExecutionException(e)); } } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java0000664000175000017500000002604312041336206033161 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.core.test; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.ListenerDispatcher; import net.floodlightcontroller.packet.Ethernet; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFType; import org.openflow.protocol.factory.BasicFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightProviderService { protected static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class); protected ConcurrentMap> listeners; protected List switchListeners; protected List haListeners; protected Map switches; protected BasicFactory factory; /** * */ public MockFloodlightProvider() { listeners = new ConcurrentHashMap>(); switches = new ConcurrentHashMap(); switchListeners = new CopyOnWriteArrayList(); haListeners = new CopyOnWriteArrayList(); factory = new BasicFactory(); } @Override public synchronized void addOFMessageListener(OFType type, IOFMessageListener listener) { ListenerDispatcher ldd = listeners.get(type); if (ldd == null) { ldd = new ListenerDispatcher(); listeners.put(type, ldd); } ldd.addListener(type, listener); } @Override public synchronized void removeOFMessageListener(OFType type, IOFMessageListener listener) { ListenerDispatcher ldd = listeners.get(type); if (ldd != null) { ldd.removeListener(listener); } } /** * @return the listeners */ public Map> getListeners() { Map> lers = new HashMap>(); for(Entry> e : listeners.entrySet()) { lers.put(e.getKey(), e.getValue().getOrderedListeners()); } return Collections.unmodifiableMap(lers); } public void clearListeners() { this.listeners.clear(); } @Override public Map getSwitches() { return this.switches; } public void setSwitches(Map switches) { this.switches = switches; } @Override public void addOFSwitchListener(IOFSwitchListener listener) { switchListeners.add(listener); } @Override public void removeOFSwitchListener(IOFSwitchListener listener) { switchListeners.remove(listener); } public void dispatchMessage(IOFSwitch sw, OFMessage msg) { dispatchMessage(sw, msg, new FloodlightContext()); } public void dispatchMessage(IOFSwitch sw, OFMessage msg, FloodlightContext bc) { List theListeners = listeners.get(msg.getType()).getOrderedListeners(); if (theListeners != null) { Command result = Command.CONTINUE; Iterator it = theListeners.iterator(); if (OFType.PACKET_IN.equals(msg.getType())) { OFPacketIn pi = (OFPacketIn)msg; Ethernet eth = new Ethernet(); eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); IFloodlightProviderService.bcStore.put(bc, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, eth); } while (it.hasNext() && !Command.STOP.equals(result)) { result = it.next().receive(sw, msg, bc); } } } public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) { List msgListeners = null; if (listeners.containsKey(m.getType())) { msgListeners = listeners.get(m.getType()).getOrderedListeners(); } if (msgListeners != null) { for (IOFMessageListener listener : msgListeners) { if (listener instanceof IOFSwitchFilter) { if (!((IOFSwitchFilter)listener).isInterested(sw)) { continue; } } if (Command.STOP.equals(listener.receive(sw, m, bc))) { break; } } } } public void handleOutgoingMessages(IOFSwitch sw, List msglist, FloodlightContext bc) { for (OFMessage m:msglist) { handleOutgoingMessage(sw, m, bc); } } /** * @return the switchListeners */ public List getSwitchListeners() { return switchListeners; } public void terminate() { } @Override public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) { dispatchMessage(sw, msg); return true; } @Override public boolean injectOfMessage(IOFSwitch sw, OFMessage msg, FloodlightContext bContext) { dispatchMessage(sw, msg, bContext); return true; } @Override public BasicFactory getOFMessageFactory() { return factory; } @Override public void run() { logListeners(); } @Override public Collection> getModuleServices() { Collection> services = new ArrayList>(1); services.add(IFloodlightProviderService.class); return services; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IFloodlightProviderService.class, this); return m; } @Override public Collection> getModuleDependencies() { return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { // TODO Auto-generated method stub } @Override public void startUp(FloodlightModuleContext context) { // TODO Auto-generated method stub } @Override public void addInfoProvider(String type, IInfoProvider provider) { // TODO Auto-generated method stub } @Override public void removeInfoProvider(String type, IInfoProvider provider) { // TODO Auto-generated method stub } @Override public Map getControllerInfo(String type) { // TODO Auto-generated method stub return null; } @Override public void addHAListener(IHAListener listener) { haListeners.add(listener); } @Override public void removeHAListener(IHAListener listener) { haListeners.remove(listener); } @Override public Role getRole() { return null; } @Override public void setRole(Role role) { } /** * Dispatches a new role change notification * @param oldRole * @param newRole */ public void dispatchRoleChanged(Role oldRole, Role newRole) { for (IHAListener rl : haListeners) { rl.roleChanged(oldRole, newRole); } } @Override public String getControllerId() { return "localhost"; } @Override public Map getControllerNodeIPs() { // TODO Auto-generated method stub return null; } @Override public long getSystemStartTime() { // TODO Auto-generated method stub return 0; } private void logListeners() { for (Map.Entry> entry : listeners.entrySet()) { OFType type = entry.getKey(); ListenerDispatcher ldd = entry.getValue(); StringBuffer sb = new StringBuffer(); sb.append("OFListeners for "); sb.append(type); sb.append(": "); for (IOFMessageListener l : ldd.getOrderedListeners()) { sb.append(l.getName()); sb.append(","); } log.debug(sb.toString()); } } @Override public void setAlwaysClearFlowsOnSwAdd(boolean value) { // TODO Auto-generated method stub } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java0000664000175000017500000001375412041336206031305 0ustar jamespagejamespagepackage net.floodlightcontroller.core.test; import java.util.ArrayList; import java.util.List; import net.floodlightcontroller.packet.DHCP; import net.floodlightcontroller.packet.DHCPOption; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.util.MACAddress; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFType; import org.openflow.protocol.OFPacketIn.OFPacketInReason; import org.openflow.protocol.factory.BasicFactory; /** * A class to that creates many types of L2/L3/L4 or OpenFlow packets. * This is used in testing. * @author alexreimers * */ public class PacketFactory { public static String broadcastMac = "ff:ff:ff:ff:ff:ff"; public static String broadcastIp = "255.255.255.255"; protected static BasicFactory OFMessageFactory = new BasicFactory(); /** * Generates a DHCP request OFPacketIn. * @param hostMac The host MAC address of for the request. * @return An OFPacketIn that contains a DHCP request packet. */ public static OFPacketIn DhcpDiscoveryRequestOFPacketIn(MACAddress hostMac) { byte[] serializedPacket = DhcpDiscoveryRequestEthernet(hostMac).serialize(); return (((OFPacketIn)OFMessageFactory .getMessage(OFType.PACKET_IN)) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setInPort((short) 1) .setPacketData(serializedPacket) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short)serializedPacket.length)); } /** * Generates a DHCP request Ethernet frame. * @param hostMac The host MAC address of for the request. * @returnAn An Ethernet frame that contains a DHCP request packet. */ public static Ethernet DhcpDiscoveryRequestEthernet(MACAddress hostMac) { List optionList = new ArrayList(); byte[] requestValue = new byte[4]; requestValue[0] = requestValue[1] = requestValue[2] = requestValue[3] = 0; DHCPOption requestOption = new DHCPOption() .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP. getValue()) .setLength((byte)4) .setData(requestValue); byte[] msgTypeValue = new byte[1]; msgTypeValue[0] = 1; // DHCP request DHCPOption msgTypeOption = new DHCPOption() .setCode(DHCP.DHCPOptionCode.OptionCode_MessageType. getValue()) .setLength((byte)1) .setData(msgTypeValue); byte[] reqParamValue = new byte[4]; reqParamValue[0] = 1; // subnet mask reqParamValue[1] = 3; // Router reqParamValue[2] = 6; // Domain Name Server reqParamValue[3] = 42; // NTP Server DHCPOption reqParamOption = new DHCPOption() .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedParameters. getValue()) .setLength((byte)4) .setData(reqParamValue); byte[] clientIdValue = new byte[7]; clientIdValue[0] = 1; // Ethernet System.arraycopy(hostMac.toBytes(), 0, clientIdValue, 1, 6); DHCPOption clientIdOption = new DHCPOption() .setCode(DHCP.DHCPOptionCode.OptionCode_ClientID. getValue()) .setLength((byte)7) .setData(clientIdValue); DHCPOption endOption = new DHCPOption() .setCode(DHCP.DHCPOptionCode.OptionCode_END. getValue()) .setLength((byte)0) .setData(null); optionList.add(requestOption); optionList.add(msgTypeOption); optionList.add(reqParamOption); optionList.add(clientIdOption); optionList.add(endOption); Ethernet requestPacket = new Ethernet(); requestPacket.setSourceMACAddress(hostMac.toBytes()) .setDestinationMACAddress(broadcastMac) .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setVersion((byte)4) .setDiffServ((byte)0) .setIdentification((short)100) .setFlags((byte)0) .setFragmentOffset((short)0) .setTtl((byte)250) .setProtocol(IPv4.PROTOCOL_UDP) .setChecksum((short)0) .setSourceAddress(0) .setDestinationAddress(broadcastIp) .setPayload( new UDP() .setSourcePort(UDP.DHCP_CLIENT_PORT) .setDestinationPort(UDP.DHCP_SERVER_PORT) .setChecksum((short)0) .setPayload( new DHCP() .setOpCode(DHCP.OPCODE_REQUEST) .setHardwareType(DHCP.HWTYPE_ETHERNET) .setHardwareAddressLength((byte)6) .setHops((byte)0) .setTransactionId(0x00003d1d) .setSeconds((short)0) .setFlags((short)0) .setClientIPAddress(0) .setYourIPAddress(0) .setServerIPAddress(0) .setGatewayIPAddress(0) .setClientHardwareAddress(hostMac.toBytes()) .setOptions(optionList)))); return requestPacket; } } floodlight-0.90/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java0000664000175000017500000000406512041336206032735 0ustar jamespagejamespagepackage net.floodlightcontroller.core.test; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.threadpool.IThreadPoolService; public class MockThreadPoolService implements IFloodlightModule, IThreadPoolService { protected ScheduledExecutorService mockExecutor = new MockScheduledExecutor(); /** * Return a mock executor that will simply execute each task * synchronously once. */ @Override public ScheduledExecutorService getScheduledExecutor() { return mockExecutor; } // IFloodlightModule @Override public Collection> getModuleServices() { Collection> l = new ArrayList>(); l.add(IThreadPoolService.class); return l; } @Override public Map, IFloodlightService> getServiceImpls() { Map, IFloodlightService> m = new HashMap, IFloodlightService>(); m.put(IThreadPoolService.class, this); // We are the class that implements the service return m; } @Override public Collection> getModuleDependencies() { // No dependencies return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { } @Override public void startUp(FloodlightModuleContext context) { // no-op } } floodlight-0.90/src/test/java/net/floodlightcontroller/topology/0000775000175000017500000000000012041336206025636 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java0000664000175000017500000004621512041336206032652 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import static org.junit.Assert.*; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.NodePortTuple; import net.floodlightcontroller.topology.TopologyInstance; import net.floodlightcontroller.topology.TopologyManager; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TopologyInstanceTest { protected static Logger log = LoggerFactory.getLogger(TopologyInstanceTest.class); protected TopologyManager topologyManager; protected FloodlightModuleContext fmc; protected MockFloodlightProvider mockFloodlightProvider; protected int DIRECT_LINK = 1; protected int MULTIHOP_LINK = 2; protected int TUNNEL_LINK = 3; @Before public void SetUp() throws Exception { fmc = new FloodlightModuleContext(); mockFloodlightProvider = new MockFloodlightProvider(); fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); MockThreadPoolService tp = new MockThreadPoolService(); topologyManager = new TopologyManager(); fmc.addService(IThreadPoolService.class, tp); topologyManager.init(fmc); tp.init(fmc); tp.startUp(fmc); } protected void verifyClusters(int[][] clusters) { verifyClusters(clusters, true); } protected void verifyClusters(int[][] clusters, boolean tunnelsEnabled) { List verifiedSwitches = new ArrayList(); // Make sure the expected cluster arrays are sorted so we can // use binarySearch to test for membership for (int i = 0; i < clusters.length; i++) Arrays.sort(clusters[i]); TopologyInstance ti = topologyManager.getCurrentInstance(tunnelsEnabled); Set switches = ti.getSwitches(); for (long sw: switches) { if (!verifiedSwitches.contains(sw)) { int[] expectedCluster = null; for (int j = 0; j < clusters.length; j++) { if (Arrays.binarySearch(clusters[j], (int) sw) >= 0) { expectedCluster = clusters[j]; break; } } if (expectedCluster != null) { Set cluster = ti.getSwitchesInOpenflowDomain(sw); assertEquals(expectedCluster.length, cluster.size()); for (long sw2: cluster) { assertTrue(Arrays.binarySearch(expectedCluster, (int)sw2) >= 0); verifiedSwitches.add(sw2); } } } } } protected void verifyExpectedBroadcastPortsInClusters(int [][][] ebp) { verifyExpectedBroadcastPortsInClusters(ebp, true); } protected void verifyExpectedBroadcastPortsInClusters(int [][][] ebp, boolean tunnelsEnabled) { NodePortTuple npt = null; Set expected = new HashSet(); for(int i=0; i computed = ti.getBroadcastNodePortsInCluster(npt.nodeId); if (computed != null) assertTrue(computed.equals(expected)); else if (computed == null) assertTrue(expected.isEmpty()); } } public void createTopologyFromLinks(int [][] linkArray) throws Exception { ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK; // Use topologymanager to write this test, it will make it a lot easier. for (int i = 0; i < linkArray.length; i++) { int [] r = linkArray[i]; if (r[4] == DIRECT_LINK) type= ILinkDiscovery.LinkType.DIRECT_LINK; else if (r[4] == MULTIHOP_LINK) type= ILinkDiscovery.LinkType.MULTIHOP_LINK; else if (r[4] == TUNNEL_LINK) type = ILinkDiscovery.LinkType.TUNNEL; topologyManager.addOrUpdateLink((long)r[0], (short)r[1], (long)r[2], (short)r[3], type); } topologyManager.createNewInstance(); } public TopologyManager getTopologyManager() { return topologyManager; } @Test public void testClusters() throws Exception { TopologyManager tm = getTopologyManager(); { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 3, 4, 2, DIRECT_LINK}, {3, 3, 4, 1, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3}, {4} }; //tm.recompute(); createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } { int [][] linkArray = { {5, 3, 6, 1, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3}, {4}, {5}, {6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } { int [][] linkArray = { {6, 1, 5, 3, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3}, {4}, {5,6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } { int [][] linkArray = { {4, 2, 2, 3, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3,4}, {5,6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } { int [][] linkArray = { {4, 3, 5, 1, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3,4}, {5,6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } { int [][] linkArray = { {5, 2, 2, 4, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3,4,5,6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } //Test 2. { int [][] linkArray = { {3, 2, 2, 2, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {4, 1, 3, 3, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {2, 4, 5, 2, DIRECT_LINK} }; int [][] expectedClusters = { {1,2,3,4,5,6} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); } // Test 3. Remove links { tm.removeLink((long)5,(short)3,(long)6,(short)1); tm.removeLink((long)6,(short)1,(long)5,(short)3); int [][] expectedClusters = { {1,2,3,4,5}, }; topologyManager.createNewInstance(); verifyClusters(expectedClusters); } // Remove Switch { tm.removeSwitch(4); int [][] expectedClusters = { {1,2,3,5}, }; topologyManager.createNewInstance(); verifyClusters(expectedClusters); } } @Test public void testLoopDetectionInSingleIsland() throws Exception { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 2, 2, 2, DIRECT_LINK}, {3, 3, 4, 1, DIRECT_LINK}, {4, 1, 3, 3, DIRECT_LINK}, {4, 2, 6, 2, DIRECT_LINK}, {6, 2, 4, 2, DIRECT_LINK}, {4, 3, 5, 1, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {5, 2, 6, 1, DIRECT_LINK}, {6, 1, 5, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3, 4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}, {1,2}, {3,1}, {3,3}, {4,1}, {4,3}, {5,1}, {4,2}, {6,2}}, }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } @Test public void testTunnelLinkDeletion() throws Exception { // +-------+ +-------+ // | | | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // // // +-------+ // | 1 | // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, TUNNEL_LINK}, {3, 1, 1, 2, TUNNEL_LINK}, {2, 2, 3, 2, TUNNEL_LINK}, {3, 2, 2, 2, TUNNEL_LINK}, {4, 2, 6, 2, DIRECT_LINK}, {6, 2, 4, 2, DIRECT_LINK}, {4, 3, 5, 1, TUNNEL_LINK}, {5, 1, 4, 3, TUNNEL_LINK}, {5, 2, 6, 1, TUNNEL_LINK}, {6, 1, 5, 2, TUNNEL_LINK}, }; int [][] expectedClusters = { {1, 2}, {4, 6}, }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}}, {{4,2}, {6,2}} }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); verifyClusters(expectedClusters, false); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts, false); } // +-------+ +-------+ // | | TUNNEL | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // | // | TUNNEL // | // +-------+ // | 1 | TUNNEL // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {3, 3, 4, 1, TUNNEL_LINK}, {4, 1, 3, 3, TUNNEL_LINK}, }; int [][] expectedClusters = { {1, 2}, {4, 6}, {3}, {5}, }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}}, {{4,2}, {6,2}} }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); verifyClusters(expectedClusters, false); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts, false); } } @Test public void testLoopDetectionWithIslands() throws Exception { // +-------+ +-------+ // | | TUNNEL | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // // // +-------+ // | 1 | TUNNEL // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {1, 1, 2, 1, TUNNEL_LINK}, {2, 1, 1, 1, TUNNEL_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 2, 2, 2, DIRECT_LINK}, {4, 2, 6, 2, TUNNEL_LINK}, {6, 2, 4, 2, TUNNEL_LINK}, {4, 3, 5, 1, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {5, 2, 6, 1, DIRECT_LINK}, {6, 1, 5, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,2}, {3,1}, {2,2}, {3,2}}, {{4,3}, {5,1}, {5,2}, {6,1}}, }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } // +-------+ +-------+ // | | TUNNEL | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // | // | TUNNEL // | // +-------+ // | 1 | TUNNEL // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {3, 3, 4, 1, TUNNEL_LINK}, {4, 1, 3, 3, TUNNEL_LINK}, }; int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,2}, {3,1}, {2,2}, {3,2}}, {{4,3}, {5,1}, {5,2}, {6,1}}, }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); verifyClusters(expectedClusters, false); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } } } floodlight-0.90/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java0000664000175000017500000001557112041336206032461 0ustar jamespagejamespagepackage net.floodlightcontroller.topology; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.TopologyManager; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TopologyManagerTest extends FloodlightTestCase { protected static Logger log = LoggerFactory.getLogger(TopologyManagerTest.class); TopologyManager tm; FloodlightModuleContext fmc; @Before public void setUp() throws Exception { super.setUp(); fmc = new FloodlightModuleContext(); fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); MockThreadPoolService tp = new MockThreadPoolService(); fmc.addService(IThreadPoolService.class, tp); tm = new TopologyManager(); tp.init(fmc); tm.init(fmc); tp.startUp(fmc); } @Test public void testBasic1() throws Exception { tm.addOrUpdateLink((long)1, (short)1, (long)2, (short)1, ILinkDiscovery.LinkType.DIRECT_LINK); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==1); assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); assertTrue(tm.getTunnelPorts().size()==0); tm.addOrUpdateLink((long)1, (short)2, (long)2, (short)2, ILinkDiscovery.LinkType.MULTIHOP_LINK); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==2); assertTrue(tm.getSwitchPorts().get((long)2).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==0); tm.addOrUpdateLink((long)1, (short)3, (long)2, (short)3, ILinkDiscovery.LinkType.TUNNEL); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==3); assertTrue(tm.getSwitchPorts().get((long)2).size()==3); assertTrue(tm.getSwitchPortLinks().size()==6); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)2, (long)2, (short)2); log.info("# of switchports. {}", tm.getSwitchPorts().get((long)1).size()); assertTrue(tm.getSwitchPorts().get((long)1).size()==2); assertTrue(tm.getSwitchPorts().get((long)2).size()==2); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)1, (long)2, (short)1); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==1); assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)3, (long)2, (short)3); assertTrue(tm.getSwitchPorts().size() == 0); assertTrue(tm.getSwitchPortLinks().size()==0); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); assertTrue(tm.getTunnelPorts().size()==0); } @Test public void testBasic2() throws Exception { tm.addOrUpdateLink((long)1, (short)1, (long)2, (short)1, ILinkDiscovery.LinkType.DIRECT_LINK); tm.addOrUpdateLink((long)2, (short)2, (long)3, (short)1, ILinkDiscovery.LinkType.MULTIHOP_LINK); tm.addOrUpdateLink((long)3, (short)2, (long)1, (short)2, ILinkDiscovery.LinkType.TUNNEL); assertTrue(tm.getSwitchPorts().size() == 3); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==2); assertTrue(tm.getSwitchPorts().get((long)2).size()==2); assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==6); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)1, (long)2, (short)1); assertTrue(tm.getSwitchPorts().size() == 3); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==1); assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==2); // nonexistent link // no null pointer exceptions. tm.removeLink((long)3, (short)1, (long)2, (short)2); assertTrue(tm.getSwitchPorts().size() == 3); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1).size()==1); assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)3, (short)2, (long)1, (short)2); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPorts().get((long)1)==null); assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPorts().get((long)3).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); assertTrue(tm.getTunnelPorts().size()==0); tm.removeLink((long)2, (short)2, (long)3, (short)1); assertTrue(tm.getSwitchPorts().size() == 0); // for two nodes. assertTrue(tm.getSwitchPortLinks().size()==0); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); assertTrue(tm.getTunnelPorts().size()==0); } @Test public void testHARoleChange() throws Exception { testBasic2(); getMockFloodlightProvider().dispatchRoleChanged(null, Role.SLAVE); assert(tm.switchPorts.isEmpty()); assert(tm.switchPortLinks.isEmpty()); assert(tm.portBroadcastDomainLinks.isEmpty()); assert(tm.tunnelLinks.isEmpty()); } } floodlight-0.90/src/test/java/net/floodlightcontroller/storage/0000775000175000017500000000000012041336206025426 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/storage/memory/0000775000175000017500000000000012041336206026736 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/storage/memory/tests/0000775000175000017500000000000012041336206030100 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/storage/memory/tests/MemoryStorageTest.java0000664000175000017500000000304412041336206034401 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.memory.tests; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.storage.tests.StorageTest; import org.junit.Before; public class MemoryStorageTest extends StorageTest { @Before public void setUp() throws Exception { storageSource = new MemoryStorageSource(); restApi = new RestApiServer(); FloodlightModuleContext fmc = new FloodlightModuleContext(); fmc.addService(IRestApiService.class, restApi); restApi.init(fmc); storageSource.init(fmc); restApi.startUp(fmc); storageSource.startUp(fmc); super.setUp(); } } floodlight-0.90/src/test/java/net/floodlightcontroller/storage/tests/0000775000175000017500000000000012041336206026570 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java0000664000175000017500000007545012041336206031712 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.storage.tests; import static org.easymock.EasyMock.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.CompoundPredicate; import net.floodlightcontroller.storage.IStorageExceptionHandler; import net.floodlightcontroller.storage.IPredicate; import net.floodlightcontroller.storage.IQuery; import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IRowMapper; import net.floodlightcontroller.storage.IStorageSourceListener; import net.floodlightcontroller.storage.NullValueStorageException; import net.floodlightcontroller.storage.OperatorPredicate; import net.floodlightcontroller.storage.RowOrdering; import net.floodlightcontroller.storage.nosql.NoSqlStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import org.junit.Test; public abstract class StorageTest extends FloodlightTestCase { protected NoSqlStorageSource storageSource; protected RestApiServer restApi; protected String PERSON_TABLE_NAME = "Person"; protected String PERSON_SSN = "SSN"; protected String PERSON_FIRST_NAME = "FirstName"; protected String PERSON_LAST_NAME = "LastName"; protected String PERSON_AGE = "Age"; protected String PERSON_REGISTERED = "Registered"; protected String[] PERSON_COLUMN_LIST = {PERSON_SSN, PERSON_FIRST_NAME, PERSON_LAST_NAME, PERSON_AGE, PERSON_REGISTERED}; class Person { private String ssn; private String firstName; private String lastName; int age; boolean registered; public Person(String ssn, String firstName, String lastName, int age, boolean registered) { this.ssn = ssn; this.firstName = firstName; this.lastName = lastName; this.age = age; this.registered = registered; } public String getSSN() { return ssn; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public boolean isRegistered() { return registered; } } class PersonRowMapper implements IRowMapper { public Object mapRow(IResultSet resultSet) { String ssn = resultSet.getString(PERSON_SSN); String firstName = resultSet.getString(PERSON_FIRST_NAME); String lastName = resultSet.getString(PERSON_LAST_NAME); int age = resultSet.getInt(PERSON_AGE); boolean registered = resultSet.getBoolean(PERSON_REGISTERED); return new Person(ssn, firstName, lastName, age, registered); } } Object[][] PERSON_INIT_DATA = { {"111-11-1111", "John", "Smith", 40, true}, {"222-22-2222", "Jim", "White", 24, false}, {"333-33-3333", "Lisa", "Jones", 27, true}, {"444-44-4444", "Susan", "Jones", 14, false}, {"555-55-5555", "Jose", "Garcia", 31, true}, {"666-66-6666", "Abigail", "Johnson", 35, false}, {"777-77-7777", "Bjorn", "Borg", 55, true}, {"888-88-8888", "John", "McEnroe", 53, false} }; Map createPersonRowValues(Object[] personData) { Map rowValues = new HashMap(); for (int i = 0; i < PERSON_COLUMN_LIST.length; i++) { rowValues.put(PERSON_COLUMN_LIST[i], personData[i]); } return rowValues; } public void insertPerson(Object[] personData) { Map rowValues = createPersonRowValues(personData); storageSource.insertRow(PERSON_TABLE_NAME, rowValues); } public void initPersons() { for (Object[] row: PERSON_INIT_DATA) { insertPerson(row); } } public void setUp() throws Exception { super.setUp(); Set indexedColumnNames = new HashSet(); indexedColumnNames.add(PERSON_LAST_NAME); storageSource.setExceptionHandler(null); storageSource.createTable(PERSON_TABLE_NAME, indexedColumnNames); storageSource.setTablePrimaryKeyName(PERSON_TABLE_NAME, PERSON_SSN); initPersons(); } public void checkExpectedResults(IResultSet resultSet, String[] columnNameList, Object[][] expectedRowList) { boolean nextResult; for (Object[] expectedRow: expectedRowList) { nextResult = resultSet.next(); assertEquals(nextResult,true); assertEquals(expectedRow.length, columnNameList.length); for (int i = 0; i < expectedRow.length; i++) { Object expectedObject = expectedRow[i]; String columnName = columnNameList[i]; if (expectedObject instanceof Boolean) assertEquals(((Boolean)expectedObject).booleanValue(), resultSet.getBoolean(columnName)); else if (expectedObject instanceof Byte) assertEquals(((Byte)expectedObject).byteValue(), resultSet.getByte(columnName)); else if (expectedObject instanceof Short) assertEquals(((Short)expectedObject).shortValue(), resultSet.getShort(columnName)); else if (expectedObject instanceof Integer) assertEquals(((Integer)expectedObject).intValue(), resultSet.getInt(columnName)); else if (expectedObject instanceof Long) assertEquals(((Long)expectedObject).longValue(), resultSet.getLong(columnName)); else if (expectedObject instanceof Float) assertEquals(((Float)expectedObject).floatValue(), resultSet.getFloat(columnName), 0.00001); else if (expectedObject instanceof Double) assertEquals(((Double)expectedObject).doubleValue(), resultSet.getDouble(columnName), 0.00001); else if (expectedObject instanceof byte[]) assertEquals((byte[])expectedObject, resultSet.getByteArray(columnName)); else if (expectedObject instanceof String) assertEquals((String)expectedObject, resultSet.getString(columnName)); else assertTrue("Unexpected column value type", false); } } nextResult = resultSet.next(); assertEquals(nextResult,false); resultSet.close(); } @Test public void testInsertRows() { IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, PERSON_INIT_DATA); } @Test public void testOperatorQuery() { Object[][] expectedResults = { {"John", "Smith", 40}, {"Jim", "White", 24}, }; String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE}; IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList, new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm"), new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, columnList, expectedResults); } @Test public void testAndQuery() { String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME}; Object[][] expectedResults = { {"Lisa", "Jones"}, {"Susan", "Jones"}, {"Jose", "Garcia"}, {"Abigail", "Johnson"}, {"John", "McEnroe"} }; IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList, new CompoundPredicate(CompoundPredicate.Operator.AND, false, new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "G"), new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.LT, "N") ), new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, columnList, expectedResults); } @Test public void testOrQuery() { String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME, PERSON_AGE}; Object[][] expectedResults = { {"John", "Smith", 40}, {"Lisa", "Jones", 27}, {"Abigail", "Johnson", 35}, {"Bjorn", "Borg", 55}, {"John", "McEnroe", 53} }; IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, columnList, new CompoundPredicate(CompoundPredicate.Operator.OR, false, new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GTE, 35), new OperatorPredicate(PERSON_FIRST_NAME, OperatorPredicate.Operator.EQ, "Lisa") ), new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, columnList, expectedResults); } @Test public void testCreateQuery() { String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME}; Object[][] expectedResults = { {"Lisa", "Jones"}, {"Susan", "Jones"} }; IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones"); IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN)); IResultSet resultSet = storageSource.executeQuery(query); checkExpectedResults(resultSet, columnList, expectedResults); } @Test public void testQueryParameters() { String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME, PERSON_AGE}; Object[][] expectedResults = { {"John", "Smith", 40}, {"Bjorn", "Borg", 55}, {"John", "McEnroe", 53} }; IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GTE, "?MinimumAge?"); IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN)); query.setParameter("MinimumAge", 40); IResultSet resultSet = storageSource.executeQuery(query); checkExpectedResults(resultSet, columnList, expectedResults); } private void checkPerson(Person person, Object[] expectedValues) { assertEquals(person.getSSN(), expectedValues[0]); assertEquals(person.getFirstName(), expectedValues[1]); assertEquals(person.getLastName(), expectedValues[2]); assertEquals(person.getAge(), expectedValues[3]); assertEquals(person.isRegistered(), expectedValues[4]); } @Test public void testRowMapper() { Object[][] expectedResults = { PERSON_INIT_DATA[2], PERSON_INIT_DATA[3] }; IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones"); IRowMapper rowMapper = new PersonRowMapper(); Object[] personList = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN), rowMapper); assertEquals(personList.length, 2); for (int i = 0; i < personList.length; i++) checkPerson((Person)personList[i], expectedResults[i]); } @Test public void testDeleteRowsDirect() { storageSource.deleteRow(PERSON_TABLE_NAME, "111-11-1111"); storageSource.deleteRow(PERSON_TABLE_NAME, "222-22-2222"); storageSource.deleteRow(PERSON_TABLE_NAME, "333-33-3333"); storageSource.deleteRow(PERSON_TABLE_NAME, "444-44-4444"); Object[][] expectedResults = { {"555-55-5555", "Jose", "Garcia", 31, true}, {"666-66-6666", "Abigail", "Johnson", 35, false}, {"777-77-7777", "Bjorn", "Borg", 55, true}, {"888-88-8888", "John", "McEnroe", 53, false} }; IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults); } @Test public void testDeleteRowsFromResultSet() { Object[][] expectedResults = { {"555-55-5555", "Jose", "Garcia", 31, true}, {"666-66-6666", "Abigail", "Johnson", 35, false}, {"777-77-7777", "Bjorn", "Borg", 55, true}, {"888-88-8888", "John", "McEnroe", 53, false} }; // Query once to delete the rows IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN)); for (int i = 0; i < 4; i++) { resultSet.next(); resultSet.deleteRow(); } resultSet.save(); resultSet.close(); // Now query again to verify that the rows were deleted resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults); } @Test public void testDeleteMatchingRows() { Object[][] expectedResults = { {"111-11-1111", "John", "Smith", 40, true}, {"777-77-7777", "Bjorn", "Borg", 55, true}, {"888-88-8888", "John", "McEnroe", 53, false} }; storageSource.deleteMatchingRows(PERSON_TABLE_NAME, new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.LT, 40)); // Now query again to verify that the rows were deleted IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults); storageSource.deleteMatchingRows(PERSON_TABLE_NAME, null); // Now query again to verify that all rows were deleted resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, new Object[0][]); } @Test public void testUpdateRowsDirect() { Object[][] expectedResults = { {"777-77-7777", "Tennis", "Borg", 60, true}, {"888-88-8888", "Tennis", "McEnroe", 60, false} }; Map updateValues = new HashMap(); updateValues.put(PERSON_FIRST_NAME, "Tennis"); updateValues.put(PERSON_AGE, 60); IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GT, 50); IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN)); while (resultSet.next()) { String key = resultSet.getString(PERSON_SSN); storageSource.updateRow(PERSON_TABLE_NAME, key, updateValues); } resultSet.close(); resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, predicate, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults); } @Test public void testUpdateRowsFromResultSet() { Object[][] expectedResults = { {"777-77-7777", "Tennis", "Borg", 60, true}, {"888-88-8888", "Tennis", "McEnroe", 60, false} }; IPredicate predicate = new OperatorPredicate(PERSON_AGE, OperatorPredicate.Operator.GT, 50); IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, null); while (resultSet.next()) { resultSet.setString(PERSON_FIRST_NAME, "Tennis"); resultSet.setInt(PERSON_AGE, 60); } resultSet.save(); resultSet.close(); resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, PERSON_COLUMN_LIST, predicate, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedResults); } @Test public void testNullValues() { IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones"); IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN)); while (resultSet.next()) { resultSet.setNull(PERSON_FIRST_NAME); resultSet.setIntegerObject(PERSON_AGE, null); } resultSet.save(); resultSet.close(); resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN)); int count = 0; while (resultSet.next()) { boolean checkNull = resultSet.isNull(PERSON_FIRST_NAME); assertTrue(checkNull); String s = resultSet.getString(PERSON_FIRST_NAME); assertEquals(s, null); checkNull = resultSet.isNull(PERSON_AGE); assertTrue(checkNull); Integer intObj = resultSet.getIntegerObject(PERSON_AGE); assertEquals(intObj, null); Short shortObj = resultSet.getShortObject(PERSON_AGE); assertEquals(shortObj, null); boolean excThrown = false; try { resultSet.getInt(PERSON_AGE); } catch (NullValueStorageException exc) { excThrown = true; } assertTrue(excThrown); count++; } resultSet.close(); assertEquals(count, 2); predicate = new OperatorPredicate(PERSON_FIRST_NAME, OperatorPredicate.Operator.EQ, null); resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN)); count = 0; while (resultSet.next()) { boolean checkNull = resultSet.isNull(PERSON_FIRST_NAME); assertTrue(checkNull); count++; checkNull = resultSet.isNull(PERSON_AGE); assertTrue(checkNull); } resultSet.close(); assertEquals(count, 2); } @Test public void testInsertNotification() { // Set up the listener and record the expected notification IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class); Set expectedKeys = new HashSet(); expectedKeys.add("999-99-9999"); mockListener.rowsModified(PERSON_TABLE_NAME, expectedKeys); replay(mockListener); // Now try it for real storageSource.addListener(PERSON_TABLE_NAME, mockListener); // Create a new person, which should trigger the listener Object[] newPerson = {"999-99-9999", "Serena", "Williams", 22, true}; insertPerson(newPerson); verify(mockListener); } @Test public void testUpdateNotification() { // Set up the listener and record the expected notification IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class); Set expectedKeys = new HashSet(); expectedKeys.add("111-11-1111"); mockListener.rowsModified(PERSON_TABLE_NAME, expectedKeys); replay(mockListener); // Now try it for real storageSource.addListener(PERSON_TABLE_NAME, mockListener); // Create a new person, which should trigger the listener Map updateValues = new HashMap(); updateValues.put(PERSON_FIRST_NAME, "Tennis"); storageSource.updateRow(PERSON_TABLE_NAME, "111-11-1111", updateValues); verify(mockListener); } @Test public void testDeleteNotification() { IStorageSourceListener mockListener = createNiceMock(IStorageSourceListener.class); Set expectedKeys = new HashSet(); expectedKeys.add("111-11-1111"); mockListener.rowsDeleted(PERSON_TABLE_NAME, expectedKeys); replay(mockListener); // Now try it for real storageSource.addListener(PERSON_TABLE_NAME, mockListener); // Create a new person, which should trigger the listener storageSource.deleteRow(PERSON_TABLE_NAME, "111-11-1111"); verify(mockListener); } public void waitForFuture(Future future) { try { future.get(10, TimeUnit.SECONDS); } catch (InterruptedException exc) { fail("Async storage operation interrupted"); } catch (ExecutionException exc) { fail("Async storage operation failed"); } catch (TimeoutException exc) { fail("Async storage operation timed out"); } } @Test public void testAsyncQuery1() { Object[][] expectedResults = { {"John", "Smith", 40}, {"Jim", "White", 24}, }; String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE}; IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm"); IQuery query = storageSource.createQuery(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN)); Future future = storageSource.executeQueryAsync(query); waitForFuture(future); try { IResultSet resultSet = future.get(); checkExpectedResults(resultSet, columnList, expectedResults); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncQuery2() { Object[][] expectedResults = { {"John", "Smith", 40}, {"Jim", "White", 24}, }; String[] columnList = {PERSON_FIRST_NAME,PERSON_LAST_NAME,PERSON_AGE}; IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.GTE, "Sm"); Future future = storageSource.executeQueryAsync(PERSON_TABLE_NAME, columnList, predicate, new RowOrdering(PERSON_SSN)); waitForFuture(future); try { IResultSet resultSet = future.get(); checkExpectedResults(resultSet, columnList, expectedResults); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncQuery3() { Object[][] expectedResults = { PERSON_INIT_DATA[2], PERSON_INIT_DATA[3] }; IPredicate predicate = new OperatorPredicate(PERSON_LAST_NAME, OperatorPredicate.Operator.EQ, "Jones"); IRowMapper rowMapper = new PersonRowMapper(); Future future = storageSource.executeQueryAsync(PERSON_TABLE_NAME, null, predicate, new RowOrdering(PERSON_SSN), rowMapper); waitForFuture(future); try { Object[] personList = future.get(); assertEquals(personList.length, 2); for (int i = 0; i < personList.length; i++) checkPerson((Person)personList[i], expectedResults[i]); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncException() { class TestExceptionHandler implements IStorageExceptionHandler { public int exceptionCount = 0; @Override public void handleException(Exception exception) { exceptionCount++; } } TestExceptionHandler exceptionHandler = new TestExceptionHandler(); storageSource.setExceptionHandler(exceptionHandler); // Use an invalid table name, which should cause the storage API call to throw // an exception, which should then be converted to an ExecutionException. Future future = storageSource.executeQueryAsync("InvalidTableName", null, null, null); try { future.get(10, TimeUnit.SECONDS); fail("Expected ExecutionException was not thrown"); } catch (ExecutionException e) { assertTrue(true); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } assertEquals(exceptionHandler.exceptionCount, 1); } @Test public void testAsyncInsertRow() { Object[][] newPersonInfo = {{"999-99-9999", "Ellen", "Wilson", 40, true}}; Map rowValues = createPersonRowValues(newPersonInfo[0]); Future future = storageSource.insertRowAsync(PERSON_TABLE_NAME, rowValues); waitForFuture(future); try { IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); Object[][] expectedPersons = Arrays.copyOf(PERSON_INIT_DATA, PERSON_INIT_DATA.length + newPersonInfo.length); System.arraycopy(newPersonInfo, 0, expectedPersons, PERSON_INIT_DATA.length, newPersonInfo.length); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncUpdateRow() { Map updateValues = new HashMap(); updateValues.put(PERSON_SSN, "777-77-7777"); updateValues.put(PERSON_FIRST_NAME, "Tennis"); updateValues.put(PERSON_AGE, 60); Future future = storageSource.updateRowAsync(PERSON_TABLE_NAME, updateValues); waitForFuture(future); try { IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777"); Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}}; checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncUpdateRow2() { Map updateValues = new HashMap(); updateValues.put(PERSON_FIRST_NAME, "Tennis"); updateValues.put(PERSON_AGE, 60); Future future = storageSource.updateRowAsync(PERSON_TABLE_NAME, "777-77-7777", updateValues); waitForFuture(future); try { IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777"); Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}}; checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncUpdateMatchingRows() { Map updateValues = new HashMap(); updateValues.put(PERSON_FIRST_NAME, "Tennis"); updateValues.put(PERSON_AGE, 60); IPredicate predicate = new OperatorPredicate(PERSON_SSN, OperatorPredicate.Operator.EQ, "777-77-7777"); Future future = storageSource.updateMatchingRowsAsync(PERSON_TABLE_NAME, predicate, updateValues); waitForFuture(future); try { IResultSet resultSet = storageSource.getRow(PERSON_TABLE_NAME, "777-77-7777"); Object[][] expectedPersons = {{"777-77-7777", "Tennis", "Borg", 60, true}}; checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncDeleteRow() { Future future = storageSource.deleteRowAsync(PERSON_TABLE_NAME, "111-11-1111"); waitForFuture(future); try { IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); Object[][] expectedPersons = Arrays.copyOfRange(PERSON_INIT_DATA, 1, PERSON_INIT_DATA.length); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncDeleteMatchingRows() { Future future = storageSource.deleteMatchingRowsAsync(PERSON_TABLE_NAME, null); waitForFuture(future); try { IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); checkExpectedResults(resultSet, PERSON_COLUMN_LIST, new Object[0][]); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } @Test public void testAsyncSave() { // Get a result set and make some changes to it IResultSet resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); resultSet.next(); resultSet.deleteRow(); resultSet.next(); resultSet.setString(PERSON_FIRST_NAME, "John"); Future future = storageSource.saveAsync(resultSet); waitForFuture(future); try { resultSet = storageSource.executeQuery(PERSON_TABLE_NAME, null, null, new RowOrdering(PERSON_SSN)); Object[][] expectedPersons = Arrays.copyOfRange(PERSON_INIT_DATA, 1, PERSON_INIT_DATA.length); expectedPersons[0][1] = "John"; checkExpectedResults(resultSet, PERSON_COLUMN_LIST, expectedPersons); } catch (Exception e) { fail("Exception thrown in async storage operation: " + e.toString()); } } } floodlight-0.90/src/test/java/net/floodlightcontroller/linkdiscovery/0000775000175000017500000000000012041336206026647 5ustar jamespagejamespagefloodlight-0.90/src/test/java/net/floodlightcontroller/linkdiscovery/internal/0000775000175000017500000000000012041336206030463 5ustar jamespagejamespage././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootfloodlight-0.90/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.javafloodlight-0.90/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTe0000664000175000017500000004471212041336206034767 0ustar jamespagejamespage/** * Copyright 2011, Big Switch Networks, Inc. * Originally created by David Erickson, Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package net.floodlightcontroller.linkdiscovery.internal; import static org.easymock.EasyMock.*; import java.util.Collections; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.linkdiscovery.LinkInfo; import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.topology.ITopologyService; import net.floodlightcontroller.topology.NodePortTuple; import net.floodlightcontroller.topology.TopologyManager; /** * * @author David Erickson (daviderickson@cs.stanford.edu) */ public class LinkDiscoveryManagerTest extends FloodlightTestCase { private TestLinkDiscoveryManager ldm; protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManagerTest.class); public class TestLinkDiscoveryManager extends LinkDiscoveryManager { public boolean isSendLLDPsCalled = false; public boolean isClearLinksCalled = false; @Override protected void discoverOnAllPorts() { isSendLLDPsCalled = true; super.discoverOnAllPorts(); } public void reset() { isSendLLDPsCalled = false; isClearLinksCalled = false; } @Override protected void clearAllLinks() { isClearLinksCalled = true; super.clearAllLinks(); } } public LinkDiscoveryManager getTopology() { return ldm; } public IOFSwitch createMockSwitch(Long id) { IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class); expect(mockSwitch.getId()).andReturn(id).anyTimes(); return mockSwitch; } @Before public void setUp() throws Exception { super.setUp(); FloodlightModuleContext cntx = new FloodlightModuleContext(); ldm = new TestLinkDiscoveryManager(); TopologyManager routingEngine = new TopologyManager(); ldm.linkDiscoveryAware = new ArrayList(); MockThreadPoolService tp = new MockThreadPoolService(); RestApiServer restApi = new RestApiServer(); cntx.addService(IRestApiService.class, restApi); cntx.addService(IThreadPoolService.class, tp); cntx.addService(IRoutingService.class, routingEngine); cntx.addService(ILinkDiscoveryService.class, ldm); cntx.addService(ITopologyService.class, ldm); cntx.addService(IStorageSourceService.class, new MemoryStorageSource()); cntx.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); restApi.init(cntx); tp.init(cntx); routingEngine.init(cntx); ldm.init(cntx); restApi.startUp(cntx); tp.startUp(cntx); routingEngine.startUp(cntx); ldm.startUp(cntx); IOFSwitch sw1 = createMockSwitch(1L); IOFSwitch sw2 = createMockSwitch(2L); Map switches = new HashMap(); switches.put(1L, sw1); switches.put(2L, sw2); getMockFloodlightProvider().setSwitches(switches); replay(sw1, sw2); } @Test public void testAddOrUpdateLink() throws Exception { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 2, 2L, 1); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); NodePortTuple srcNpt = new NodePortTuple(1L, 2); NodePortTuple dstNpt = new NodePortTuple(2L, 1); // check invariants hold assertNotNull(topology.switchLinks.get(lt.getSrc())); assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); assertNotNull(topology.portLinks.get(srcNpt)); assertTrue(topology.portLinks.get(srcNpt).contains(lt)); assertNotNull(topology.portLinks.get(dstNpt)); assertTrue(topology.portLinks.get(dstNpt).contains(lt)); assertTrue(topology.links.containsKey(lt)); } @Test public void testDeleteLink() throws Exception { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 2, 2L, 1); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); topology.deleteLinks(Collections.singletonList(lt), "Test"); // check invariants hold assertNull(topology.switchLinks.get(lt.getSrc())); assertNull(topology.switchLinks.get(lt.getDst())); assertNull(topology.portLinks.get(lt.getSrc())); assertNull(topology.portLinks.get(lt.getDst())); assertTrue(topology.links.isEmpty()); } @Test public void testAddOrUpdateLinkToSelf() throws Exception { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 2, 2L, 3); NodePortTuple srcNpt = new NodePortTuple(1L, 2); NodePortTuple dstNpt = new NodePortTuple(2L, 3); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); // check invariants hold assertNotNull(topology.switchLinks.get(lt.getSrc())); assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); assertNotNull(topology.portLinks.get(srcNpt)); assertTrue(topology.portLinks.get(srcNpt).contains(lt)); assertNotNull(topology.portLinks.get(dstNpt)); assertTrue(topology.portLinks.get(dstNpt).contains(lt)); assertTrue(topology.links.containsKey(lt)); } @Test public void testDeleteLinkToSelf() throws Exception { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 2, 1L, 3); NodePortTuple srcNpt = new NodePortTuple(1L, 2); NodePortTuple dstNpt = new NodePortTuple(2L, 3); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); topology.deleteLinks(Collections.singletonList(lt), "Test to self"); // check invariants hold assertNull(topology.switchLinks.get(lt.getSrc())); assertNull(topology.switchLinks.get(lt.getDst())); assertNull(topology.portLinks.get(srcNpt)); assertNull(topology.portLinks.get(dstNpt)); assertTrue(topology.links.isEmpty()); } @Test public void testRemovedSwitch() { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 2, 2L, 1); NodePortTuple srcNpt = new NodePortTuple(1L, 2); NodePortTuple dstNpt = new NodePortTuple(2L, 1); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); IOFSwitch sw1 = getMockFloodlightProvider().getSwitches().get(1L); IOFSwitch sw2 = getMockFloodlightProvider().getSwitches().get(2L); // Mock up our expected behavior topology.removedSwitch(sw1); verify(sw1, sw2); // check invariants hold assertNull(topology.switchLinks.get(lt.getSrc())); assertNull(topology.switchLinks.get(lt.getDst())); assertNull(topology.portLinks.get(srcNpt)); assertNull(topology.portLinks.get(dstNpt)); assertTrue(topology.links.isEmpty()); } @Test public void testRemovedSwitchSelf() { LinkDiscoveryManager topology = getTopology(); IOFSwitch sw1 = createMockSwitch(1L); replay(sw1); Link lt = new Link(1L, 2, 1L, 3); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); // Mock up our expected behavior topology.removedSwitch(sw1); verify(sw1); // check invariants hold assertNull(topology.switchLinks.get(lt.getSrc())); assertNull(topology.portLinks.get(lt.getSrc())); assertNull(topology.portLinks.get(lt.getDst())); assertTrue(topology.links.isEmpty()); } @Test public void testAddUpdateLinks() throws Exception { LinkDiscoveryManager topology = getTopology(); Link lt = new Link(1L, 1, 2L, 1); NodePortTuple srcNpt = new NodePortTuple(1L, 1); NodePortTuple dstNpt = new NodePortTuple(2L, 1); LinkInfo info; info = new LinkInfo(System.currentTimeMillis() - 40000, System.currentTimeMillis() - 40000, null, 0, 0); topology.addOrUpdateLink(lt, info); // check invariants hold assertNotNull(topology.switchLinks.get(lt.getSrc())); assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); assertNotNull(topology.portLinks.get(srcNpt)); assertTrue(topology.portLinks.get(srcNpt).contains(lt)); assertNotNull(topology.portLinks.get(dstNpt)); assertTrue(topology.portLinks.get(dstNpt).contains(lt)); assertTrue(topology.links.containsKey(lt)); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); topology.timeoutLinks(); info = new LinkInfo(System.currentTimeMillis(),/* firstseen */ null,/* unicast */ System.currentTimeMillis(), 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.links.get(lt).getUnicastValidTime() == null); assertTrue(topology.links.get(lt).getMulticastValidTime() != null); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Add a link info based on info that woudld be obtained from unicast LLDP // Setting the unicast LLDP reception time to be 40 seconds old, so we can use // this to test timeout after this test. Although the info is initialized // with LT_OPENFLOW_LINK, the link property should be changed to LT_NON_OPENFLOW // by the addOrUpdateLink method. info = new LinkInfo(System.currentTimeMillis() - 40000, System.currentTimeMillis() - 40000, null, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); // Expect to timeout the unicast Valid Time, but not the multicast Valid time // So the link type should go back to non-openflow link. topology.timeoutLinks(); assertTrue(topology.links.get(lt).getUnicastValidTime() == null); assertTrue(topology.links.get(lt).getMulticastValidTime() != null); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Set the multicastValidTime to be old and see if that also times out. info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); topology.timeoutLinks(); assertTrue(topology.links.get(lt) == null); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); // Test again only with multicast LLDP info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.links.get(lt).getUnicastValidTime() == null); assertTrue(topology.links.get(lt).getMulticastValidTime() != null); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Call timeout and check if link is no longer present. topology.timeoutLinks(); assertTrue(topology.links.get(lt) == null); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); // Start clean and see if loops are also added. lt = new Link(1L, 1, 1L, 2); srcNpt = new NodePortTuple(1L, 1); dstNpt = new NodePortTuple(1L, 2); info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Start clean and see if loops are also added. lt = new Link(1L, 1, 1L, 3); srcNpt = new NodePortTuple(1L, 1); dstNpt = new NodePortTuple(1L, 3); info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Start clean and see if loops are also added. lt = new Link(1L, 4, 1L, 5); srcNpt = new NodePortTuple(1L, 4); dstNpt = new NodePortTuple(1L, 5); info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); // Start clean and see if loops are also added. lt = new Link(1L, 3, 1L, 5); srcNpt = new NodePortTuple(1L, 3); dstNpt = new NodePortTuple(1L, 5); info = new LinkInfo(System.currentTimeMillis() - 40000, null, System.currentTimeMillis() - 40000, 0, 0); topology.addOrUpdateLink(lt, info); assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); } @Test public void testHARoleChange() throws Exception { LinkDiscoveryManager topology = getTopology(); IOFSwitch sw1 = createMockSwitch(1L); IOFSwitch sw2 = createMockSwitch(2L); replay(sw1, sw2); Link lt = new Link(1L, 2, 2L, 1); NodePortTuple srcNpt = new NodePortTuple(1L, 2); NodePortTuple dstNpt = new NodePortTuple(2L, 1); LinkInfo info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); topology.addOrUpdateLink(lt, info); // check invariants hold assertNotNull(topology.switchLinks.get(lt.getSrc())); assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); assertNotNull(topology.portLinks.get(srcNpt)); assertTrue(topology.portLinks.get(srcNpt).contains(lt)); assertNotNull(topology.portLinks.get(dstNpt)); assertTrue(topology.portLinks.get(dstNpt).contains(lt)); assertTrue(topology.links.containsKey(lt)); // check that it clears from memory getMockFloodlightProvider().dispatchRoleChanged(null, Role.SLAVE); assertTrue(topology.switchLinks.isEmpty()); getMockFloodlightProvider().dispatchRoleChanged(Role.SLAVE, Role.MASTER); // check that lldps were sent assertTrue(ldm.isSendLLDPsCalled); assertTrue(ldm.isClearLinksCalled); ldm.reset(); } } floodlight-0.90/src/test/java/org/0000775000175000017500000000000012041336206017524 5ustar jamespagejamespagefloodlight-0.90/src/test/java/org/openflow/0000775000175000017500000000000012041336206021355 5ustar jamespagejamespagefloodlight-0.90/src/test/java/org/openflow/protocol/0000775000175000017500000000000012041336206023216 5ustar jamespagejamespagefloodlight-0.90/src/test/java/org/openflow/protocol/OFSetConfigTest.java0000664000175000017500000000255612041336206027037 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFSetConfigTest extends OFTestCase { public void testWriteRead() throws Exception { OFGetConfigReply msg = (OFGetConfigReply) messageFactory .getMessage(OFType.GET_CONFIG_REPLY); msg.setFlags((short) 1); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.GET_CONFIG_REPLY, msg.getType()); TestCase.assertEquals((short)1, msg.getFlags()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFVendorTest.java0000664000175000017500000001600612041336206026406 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.Arrays; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.vendor.OFByteArrayVendorData; import org.openflow.protocol.vendor.OFBasicVendorDataType; import org.openflow.protocol.vendor.OFBasicVendorId; import org.openflow.protocol.vendor.OFVendorData; import org.openflow.protocol.vendor.OFVendorId; import org.openflow.util.OFTestCase; public class OFVendorTest extends OFTestCase { public static int ACME_VENDOR_ID = 0x00112233; static class AcmeVendorData implements OFVendorData { protected int dataType; public int getLength() { return 4; } public void readFrom(ChannelBuffer data, int length) { dataType = data.readInt(); } public void writeTo(ChannelBuffer data) { data.writeInt(dataType); } } static class AcmeVendorData1 extends AcmeVendorData { public short flags; public short value; public static int DATA_TYPE = 1; public AcmeVendorData1() { } public AcmeVendorData1(short flags, short value) { this.dataType = DATA_TYPE; this.flags = flags; this.value = value; } public short getFlags() { return flags; } public short getValue() { return value; } public int getLength() { return 8; } public void readFrom(ChannelBuffer data, int length) { super.readFrom(data, length); flags = data.readShort(); value = data.readShort(); } public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(flags); data.writeShort(value); } public static Instantiable getInstantiable() { return new Instantiable() { public OFVendorData instantiate() { return new AcmeVendorData1(); } }; } } static class AcmeVendorData2 extends AcmeVendorData { public int type; public int subtype; public static int DATA_TYPE = 2; public AcmeVendorData2() { } public AcmeVendorData2(int type, int subtype) { this.dataType = DATA_TYPE; this.type = type; this.subtype = subtype; } public int getType() { return type; } public int getSubtype() { return subtype; } public int getLength() { return 12; } public void readFrom(ChannelBuffer data, int length) { super.readFrom(data, length); type = data.readShort(); subtype = data.readShort(); } public void writeTo(ChannelBuffer data) { super.writeTo(data); data.writeShort(type); data.writeShort(subtype); } public static Instantiable getInstantiable() { return new Instantiable() { public OFVendorData instantiate() { return new AcmeVendorData2(); } }; } } { OFBasicVendorId acmeVendorId = new OFBasicVendorId(ACME_VENDOR_ID, 4); OFVendorId.registerVendorId(acmeVendorId); OFBasicVendorDataType acmeVendorData1 = new OFBasicVendorDataType( AcmeVendorData1.DATA_TYPE, AcmeVendorData1.getInstantiable()); acmeVendorId.registerVendorDataType(acmeVendorData1); OFBasicVendorDataType acmeVendorData2 = new OFBasicVendorDataType( AcmeVendorData2.DATA_TYPE, AcmeVendorData2.getInstantiable()); acmeVendorId.registerVendorDataType(acmeVendorData2); } private OFVendor makeVendorMessage(int vendor) { OFVendor msg = (OFVendor) messageFactory.getMessage(OFType.VENDOR); msg.setVendorDataFactory(new BasicFactory()); msg.setVendor(vendor); return msg; } public void testWriteRead() throws Exception { OFVendor msg = makeVendorMessage(1); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(1, msg.getVendor()); } public void testVendorData() throws Exception { OFVendor msg = makeVendorMessage(ACME_VENDOR_ID); OFVendorData vendorData = new AcmeVendorData1((short)11, (short)22); msg.setVendorData(vendorData); msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); assertEquals(ACME_VENDOR_ID, msg.getVendor()); AcmeVendorData1 vendorData1 = (AcmeVendorData1) msg.getVendorData(); assertEquals(11, vendorData1.getFlags()); assertEquals(22, vendorData1.getValue()); vendorData = new AcmeVendorData2(33, 44); msg.setVendorData(vendorData); msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); assertEquals(ACME_VENDOR_ID, msg.getVendor()); AcmeVendorData2 vendorData2 = (AcmeVendorData2) msg.getVendorData(); assertEquals(33, vendorData2.getType()); assertEquals(44, vendorData2.getSubtype()); final int DUMMY_VENDOR_ID = 55; msg.setVendor(DUMMY_VENDOR_ID); byte[] genericVendorDataBytes = new byte[] {0x55, 0x66}; vendorData = new OFByteArrayVendorData(genericVendorDataBytes); msg.setVendorData(vendorData); msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength()); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); assertEquals(DUMMY_VENDOR_ID, msg.getVendor()); OFByteArrayVendorData genericVendorData = (OFByteArrayVendorData) msg.getVendorData(); assertTrue(Arrays.equals(genericVendorDataBytes, genericVendorData.getBytes())); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFPortConfigTest.java0000664000175000017500000000256712041336206027232 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFPortConfigTest extends OFTestCase { public void testWriteRead() throws Exception { OFPortMod msg = (OFPortMod) messageFactory .getMessage(OFType.PORT_MOD); msg.setHardwareAddress(new byte[6]); msg.portNumber = 1; ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.PORT_MOD, msg.getType()); TestCase.assertEquals(1, msg.getPortNumber()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFErrorTest.java0000664000175000017500000000756112041336206026250 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.List; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.OFError.OFErrorType; import org.openflow.protocol.OFError.OFHelloFailedCode; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.MessageParseException; import org.openflow.protocol.factory.OFMessageFactory; import org.openflow.util.OFTestCase; public class OFErrorTest extends OFTestCase { public void testWriteRead() throws Exception { OFError msg = (OFError) messageFactory.getMessage(OFType.ERROR); msg.setMessageFactory(messageFactory); msg.setErrorType((short) OFErrorType.OFPET_HELLO_FAILED.getValue()); msg.setErrorCode((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal()); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(), msg.getErrorType()); TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal(), msg.getErrorType()); TestCase.assertNull(msg.getOffendingMsg()); msg.setOffendingMsg(new OFHello()); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals((short) OFErrorType.OFPET_HELLO_FAILED.getValue(), msg.getErrorType()); TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE .ordinal(), msg.getErrorType()); TestCase.assertNotNull(msg.getOffendingMsg()); TestCase.assertEquals(OFHello.MINIMUM_LENGTH, msg.getOffendingMsg().length); } public void testGarbageAtEnd() throws MessageParseException { // This is a OFError msg (12 bytes), that encaps a OFVendor msg (24 // bytes) // AND some zeros at the end (40 bytes) for a total of 76 bytes // THIS is what an NEC sends in reply to Nox's VENDOR request byte[] oferrorRaw = { 0x01, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x10, (byte) 0xcc, 0x00, 0x01, 0x00, 0x01, 0x01, 0x04, 0x00, 0x18, 0x00, 0x00, 0x10, (byte) 0xcc, 0x00, 0x00, 0x23, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; OFMessageFactory factory = new BasicFactory(); ChannelBuffer oferrorBuf = ChannelBuffers.wrappedBuffer(oferrorRaw); List msg = factory.parseMessage(oferrorBuf); TestCase.assertNotNull(msg); TestCase.assertEquals(msg.size(), 1); TestCase.assertEquals(76, msg.get(0).getLengthU()); ChannelBuffer out = ChannelBuffers.dynamicBuffer(); msg.get(0).writeTo(out); TestCase.assertEquals(76, out.readableBytes()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java0000664000175000017500000000242712041336206030112 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFBarrierRequestTest extends OFTestCase { public void testWriteRead() throws Exception { OFBarrierRequest msg = (OFBarrierRequest) messageFactory .getMessage(OFType.BARRIER_REQUEST); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.BARRIER_REQUEST, msg.getType()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java0000664000175000017500000000241512041336206027552 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFBarrierReplyTest extends OFTestCase { public void testWriteRead() throws Exception { OFBarrierReply msg = (OFBarrierReply) messageFactory .getMessage(OFType.BARRIER_REPLY); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.BARRIER_REPLY, msg.getType()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java0000664000175000017500000000420512041336206027741 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFFeaturesReplyTest extends OFTestCase { public void testWriteRead() throws Exception { OFFeaturesReply ofr = (OFFeaturesReply) messageFactory .getMessage(OFType.FEATURES_REPLY); List ports = new ArrayList(); OFPhysicalPort port = new OFPhysicalPort(); port.setHardwareAddress(new byte[6]); port.setName("eth0"); ports.add(port); ofr.setPorts(ports); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); ofr.writeTo(bb); ofr.readFrom(bb); TestCase.assertEquals(1, ofr.getPorts().size()); TestCase.assertEquals("eth0", ofr.getPorts().get(0).getName()); // test a 15 character name ofr.getPorts().get(0).setName("012345678901234"); bb.clear(); ofr.writeTo(bb); ofr.readFrom(bb); TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName()); // test a 16 character name getting truncated ofr.getPorts().get(0).setName("0123456789012345"); bb.clear(); ofr.writeTo(bb); ofr.readFrom(bb); TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFMatchTest.java0000664000175000017500000000651612041336206026212 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; public class OFMatchTest extends TestCase { public void testFromString() { OFMatch correct = new OFMatch(); OFMatch tester = new OFMatch(); // Various combinations of "all"/"any" tester.fromString("OFMatch[]"); // correct is already wildcarded TestCase.assertEquals(correct, tester); tester.fromString("all"); TestCase.assertEquals(correct, tester); tester.fromString("ANY"); TestCase.assertEquals(correct, tester); tester.fromString(""); TestCase.assertEquals(correct, tester); tester.fromString("[]"); TestCase.assertEquals(correct, tester); // ip_src correct.setWildcards(~OFMatch.OFPFW_NW_SRC_MASK); correct.setNetworkSource(0x01010203); tester.fromString("nw_src=1.1.2.3"); TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester .getNetworkSourceMaskLen()); TestCase.assertEquals(correct, tester); tester.fromString("IP_sRc=1.1.2.3"); TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester .getNetworkSourceMaskLen()); TestCase.assertEquals(correct, tester); // 0xVlan correct = new OFMatch(); correct.setDataLayerVirtualLan((short)65535); correct.setWildcards(~OFMatch.OFPFW_DL_VLAN); tester = new OFMatch(); tester.fromString("dl_vlan=0xffff"); TestCase.assertEquals(correct, tester); } public void testToString() { OFMatch match = new OFMatch(); match.fromString("nw_dst=3.4.5.6/8"); TestCase.assertEquals(8, match.getNetworkDestinationMaskLen()); String correct = "OFMatch[nw_dst=3.0.0.0/8]"; String tester = match.toString(); TestCase.assertEquals(correct, tester); tester = "OFMatch[dl_type=35020]"; correct = "OFMatch[dl_type=0x88cc]"; match = new OFMatch(); match.fromString(tester); TestCase.assertEquals(correct, match.toString()); OFMatch match2 = new OFMatch(); match2.fromString(correct); TestCase.assertEquals(match, match2); } public void testClone() { OFMatch match1 = new OFMatch(); OFMatch match2 = match1.clone(); TestCase.assertEquals(match1, match2); match2.setNetworkProtocol((byte) 4); match2.setWildcards(match2.getWildcards() & ~OFMatch.OFPFW_NW_PROTO); TestCase.assertNotSame(match1, match2); } public void testIpToString() { String test = OFMatch.ipToString(-1); TestCase.assertEquals("255.255.255.255", test); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java0000664000175000017500000001016712041336206030321 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.List; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.OFMessageFactory; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.util.OFTestCase; public class OFStatisticsReplyTest extends OFTestCase { public void testOFFlowStatisticsReply() throws Exception { byte[] packet = new byte[] { 0x01, 0x11, 0x01, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, (byte) 0xa6, (byte) 0xa6, 0x00, (byte) 0xff, (byte) 0xff, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xc4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x06, 0x00, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x2f, (byte) 0xfa, 0x40, (byte) 0xff, (byte) 0xff, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, (byte) 0xff, (byte) 0xff, 0x00, 0x62, 0x08, 0x00, 0x00, 0x01, 0x62, 0x37, 0x0a, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, (byte) 0xc5, 0x2a, (byte) 0x80, (byte) 0xff, (byte) 0xff, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xc4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00 }; OFMessageFactory factory = new BasicFactory(); ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet); List msg = factory.parseMessage(packetBuf); TestCase.assertNotNull(msg); TestCase.assertEquals(msg.size(), 1); TestCase.assertTrue(msg.get(0) instanceof OFStatisticsReply); OFStatisticsReply sr = (OFStatisticsReply) msg.get(0); TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType()); TestCase.assertEquals(3, sr.getStatistics().size()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java0000664000175000017500000000253512041336206030034 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFGetConfigReplyTest extends OFTestCase { public void testWriteRead() throws Exception { OFSetConfig msg = (OFSetConfig) messageFactory .getMessage(OFType.SET_CONFIG); msg.setFlags((short) 1); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.SET_CONFIG, msg.getType()); TestCase.assertEquals((short)1, msg.getFlags()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java0000664000175000017500000000244312041336206030367 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.util.OFTestCase; public class OFGetConfigRequestTest extends OFTestCase { public void testWriteRead() throws Exception { OFGetConfigRequest msg = (OFGetConfigRequest) messageFactory .getMessage(OFType.GET_CONFIG_REQUEST); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.GET_CONFIG_REQUEST, msg.getType()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java0000664000175000017500000000767212041336206030665 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.List; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.OFMessageFactory; import org.openflow.protocol.statistics.OFFlowStatisticsRequest; import org.openflow.protocol.statistics.OFStatisticsType; import org.openflow.protocol.statistics.OFVendorStatistics; import org.openflow.util.OFTestCase; public class OFStatisticsRequestTest extends OFTestCase { public void testOFFlowStatisticsRequest() throws Exception { byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x38, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, 0x00, (byte) 0xff, (byte) 0xff }; OFMessageFactory factory = new BasicFactory(); ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet); List msg = factory.parseMessage(packetBuf); TestCase.assertNotNull(msg); TestCase.assertEquals(msg.size(), 1); TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest); OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0); TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType()); TestCase.assertEquals(1, sr.getStatistics().size()); TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFFlowStatisticsRequest); } public void testOFStatisticsRequestVendor() throws Exception { byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x63, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, (byte) 0xe0, 0x00, 0x11, 0x00, 0x0c, 0x29, (byte) 0xc5, (byte) 0x95, 0x57, 0x02, 0x25, 0x5c, (byte) 0xca, 0x00, 0x02, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, 0x4e, 0x20 }; OFMessageFactory factory = new BasicFactory(); ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet); List msg = factory.parseMessage(packetBuf); TestCase.assertNotNull(msg); TestCase.assertEquals(msg.size(), 1); TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest); OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0); TestCase.assertEquals(OFStatisticsType.VENDOR, sr.getStatisticType()); TestCase.assertEquals(1, sr.getStatistics().size()); TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFVendorStatistics); TestCase.assertEquals(68, ((OFVendorStatistics)sr.getStatistics().get(0)).getLength()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFTypeTest.java0000664000175000017500000000231512041336206026070 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.junit.Test; public class OFTypeTest extends TestCase { public void testOFTypeCreate() throws Exception { OFType foo = OFType.HELLO; Class c = foo.toClass(); TestCase.assertEquals(c, OFHello.class); } @Test public void testMapping() throws Exception { TestCase.assertEquals(OFType.HELLO, OFType.valueOf((byte) 0)); TestCase.assertEquals(OFType.BARRIER_REPLY, OFType.valueOf((byte) 19)); } } floodlight-0.90/src/test/java/org/openflow/protocol/BasicFactoryTest.java0000664000175000017500000000561412041336206027300 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.MessageParseException; import org.openflow.util.U16; import junit.framework.TestCase; public class BasicFactoryTest extends TestCase { public void testCreateAndParse() throws MessageParseException { BasicFactory factory = new BasicFactory(); OFMessage m = factory.getMessage(OFType.HELLO); m.setVersion((byte) 1); m.setType(OFType.ECHO_REQUEST); m.setLength(U16.t(8)); m.setXid(0xdeadbeef); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); ChannelBuffer bb2 = ChannelBuffers.dynamicBuffer(); m.writeTo(bb); bb2.writeBytes(bb, bb.readableBytes()-1); TestCase.assertNull(factory.parseMessage(bb2)); bb2.writeByte(bb.readByte()); List message = factory.parseMessage(bb2); TestCase.assertNotNull(message); TestCase.assertEquals(message.size(), 1); TestCase.assertTrue(message.get(0).getType() == OFType.ECHO_REQUEST); } public void testInvalidMsgParse() throws MessageParseException { BasicFactory factory = new BasicFactory(); OFMessage m = factory.getMessage(OFType.HELLO); m.setVersion((byte) 1); m.setType(OFType.ECHO_REQUEST); m.setLength(U16.t(16)); m.setXid(0xdeadbeef); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); m.writeTo(bb); List message = factory.parseMessage(bb); TestCase.assertNull(message); } public void testCurrouptedMsgParse() throws MessageParseException { BasicFactory factory = new BasicFactory(); OFMessage m = factory.getMessage(OFType.HELLO); m.setVersion((byte) 1); m.setType(OFType.ERROR); m.setLength(U16.t(8)); m.setXid(0xdeadbeef); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); m.writeTo(bb); try { factory.parseMessage(bb); } catch(Exception e) { TestCase.assertEquals(MessageParseException.class, e.getClass()); } } } floodlight-0.90/src/test/java/org/openflow/protocol/OFPortStatusTest.java0000664000175000017500000000323512041336206027301 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.OFPortStatus.OFPortReason; import org.openflow.util.OFTestCase; public class OFPortStatusTest extends OFTestCase { public void testWriteRead() throws Exception { OFPortStatus msg = (OFPortStatus) messageFactory .getMessage(OFType.PORT_STATUS); msg.setDesc(new OFPhysicalPort()); msg.getDesc().setHardwareAddress(new byte[6]); msg.getDesc().setName("eth0"); msg.setReason((byte) OFPortReason.OFPPR_ADD.ordinal()); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.PORT_STATUS, msg.getType()); TestCase.assertEquals((byte) OFPortReason.OFPPR_ADD.ordinal(), msg .getReason()); TestCase.assertNotNull(msg.getDesc()); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java0000664000175000017500000000247512041336206030152 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.junit.Test; import org.openflow.protocol.statistics.OFStatisticsType; public class OFStatisticsTypeTest extends TestCase { @Test public void testMapping() throws Exception { TestCase.assertEquals(OFStatisticsType.DESC, OFStatisticsType.valueOf((short) 0, OFType.STATS_REQUEST)); TestCase.assertEquals(OFStatisticsType.QUEUE, OFStatisticsType.valueOf((short) 5, OFType.STATS_REQUEST)); TestCase.assertEquals(OFStatisticsType.VENDOR, OFStatisticsType.valueOf((short) 0xffff, OFType.STATS_REQUEST)); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java0000664000175000017500000000216012041336206031113 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; public class OFMessageContextStoreTest extends TestCase { public void testStoreAndGet() { OFMessage msg = new OFMessage(); OFMessageContextStore store = new OFMessageContextStore(msg, this.getName()); String key = "mykey"; String value = "myvalue"; store.put(key, value); TestCase.assertEquals(value, store.get(key)); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFActionTypeTest.java0000664000175000017500000000234312041336206027227 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import org.junit.Test; import org.openflow.protocol.action.OFActionType; import junit.framework.TestCase; public class OFActionTypeTest extends TestCase { @Test public void testMapping() throws Exception { TestCase.assertEquals(OFActionType.OUTPUT, OFActionType.valueOf((short) 0)); TestCase.assertEquals(OFActionType.OPAQUE_ENQUEUE, OFActionType.valueOf((short) 11)); TestCase.assertEquals(OFActionType.VENDOR, OFActionType.valueOf((short) 0xffff)); } } floodlight-0.90/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java0000664000175000017500000000321012041336206027373 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.protocol; import junit.framework.TestCase; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.openflow.protocol.OFFlowRemoved.OFFlowRemovedReason; import org.openflow.util.OFTestCase; public class OFFlowRemovedTest extends OFTestCase { public void testWriteRead() throws Exception { OFFlowRemoved msg = (OFFlowRemoved) messageFactory .getMessage(OFType.FLOW_REMOVED); msg.setMatch(new OFMatch()); byte[] hwAddr = new byte[6]; msg.getMatch().setDataLayerDestination(hwAddr); msg.getMatch().setDataLayerSource(hwAddr); msg.setReason(OFFlowRemovedReason.OFPRR_DELETE); ChannelBuffer bb = ChannelBuffers.dynamicBuffer(); bb.clear(); msg.writeTo(bb); msg.readFrom(bb); TestCase.assertEquals(OFType.FLOW_REMOVED, msg.getType()); TestCase.assertEquals(OFFlowRemovedReason.OFPRR_DELETE, msg.getReason()); } } floodlight-0.90/src/test/java/org/openflow/util/0000775000175000017500000000000012041336206022332 5ustar jamespagejamespagefloodlight-0.90/src/test/java/org/openflow/util/U8Test.java0000664000175000017500000000203412041336206024330 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import junit.framework.TestCase; public class U8Test extends TestCase { /** * Tests that we correctly translate unsigned values in and out of a byte * @throws Exception */ public void test() throws Exception { short val = 0xff; TestCase.assertEquals(-1, U8.t(val)); TestCase.assertEquals(val, U8.f((byte)-1)); } } floodlight-0.90/src/test/java/org/openflow/util/U16Test.java0000664000175000017500000000214212041336206024407 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import junit.framework.TestCase; public class U16Test extends TestCase { /** * Tests that we correctly translate unsigned values in and out of a short * @throws Exception */ public void test() throws Exception { int val = 0xffff; TestCase.assertEquals((short)-1, U16.t(val)); TestCase.assertEquals((short)32767, U16.t(0x7fff)); TestCase.assertEquals(val, U16.f((short)-1)); } } floodlight-0.90/src/test/java/org/openflow/util/U32Test.java0000664000175000017500000000203712041336206024410 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import junit.framework.TestCase; public class U32Test extends TestCase { /** * Tests that we correctly translate unsigned values in and out of an int * @throws Exception */ public void test() throws Exception { long val = 0xffffffffL; TestCase.assertEquals(-1, U32.t(val)); TestCase.assertEquals(val, U32.f(-1)); } } floodlight-0.90/src/test/java/org/openflow/util/UnsignedTest.java0000664000175000017500000000567612041336206025627 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.math.BigInteger; import java.nio.ByteBuffer; import junit.framework.TestCase; public class UnsignedTest extends TestCase { public static String ULONG_MAX = "18446744073709551615"; /** * Tests that we correctly extract an unsigned long into a BigInteger * @throws Exception */ public void testGetUnsignedLong() throws Exception { ByteBuffer bb = ByteBuffer.allocate(8); bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff); bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff); bb.position(0); bb.limit(8); BigInteger bi = Unsigned.getUnsignedLong(bb); BigInteger uLongMax = new BigInteger(ULONG_MAX); for (int i = 0; i < uLongMax.bitCount(); ++i) { TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i), uLongMax.testBit(i) == bi.testBit(i)); } TestCase.assertEquals(ULONG_MAX, bi.toString()); bb = ByteBuffer.allocate(10); bb.put((byte)0x00); bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff); bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff); bb.put((byte)0x00); bb.position(0); bb.limit(10); bi = Unsigned.getUnsignedLong(bb, 1); uLongMax = new BigInteger(ULONG_MAX); for (int i = 0; i < uLongMax.bitCount(); ++i) { TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i), uLongMax.testBit(i) == bi.testBit(i)); } TestCase.assertEquals(ULONG_MAX, bi.toString()); } /** * Tests that we correctly put an unsigned long into a ByteBuffer * @throws Exception */ public void testPutUnsignedLong() throws Exception { ByteBuffer bb = ByteBuffer.allocate(8); BigInteger uLongMax = new BigInteger(ULONG_MAX); Unsigned.putUnsignedLong(bb, uLongMax); for (int i = 0; i < 8; ++i) { TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " + bb.get(i), (bb.get(i) & (short)0xff) == 0xff); } bb = ByteBuffer.allocate(10); Unsigned.putUnsignedLong(bb, uLongMax, 1); int offset = 1; for (int i = 0; i < 8; ++i) { TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " + bb.get(offset+i), (bb.get(offset+i) & (short)0xff) == 0xff); } } } floodlight-0.90/src/test/java/org/openflow/util/U64Test.java0000664000175000017500000000213612041336206024415 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import java.math.BigInteger; import junit.framework.TestCase; public class U64Test extends TestCase { /** * Tests that we correctly translate unsigned values in and out of a long * @throws Exception */ public void test() throws Exception { BigInteger val = new BigInteger("ffffffffffffffff", 16); TestCase.assertEquals(-1, U64.t(val)); TestCase.assertEquals(val, U64.f(-1)); } } floodlight-0.90/src/test/java/org/openflow/util/HexStringTest.java0000664000175000017500000000514112041336206025751 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import org.junit.Test; import junit.framework.TestCase; /** * Does hexstring conversion work? * * @author Rob Sherwood (rob.sherwood@stanford.edu) * */ public class HexStringTest extends TestCase { @Test public void testMarshalling() throws Exception { String dpidStr = "00:00:00:23:20:2d:16:71"; long dpid = HexString.toLong(dpidStr); String testStr = HexString.toHexString(dpid); TestCase.assertEquals(dpidStr, testStr); } @Test public void testToLong() { String dpidStr = "3e:1f:01:fc:72:8c:63:31"; long valid = 0x3e1f01fc728c6331L; long testLong = HexString.toLong(dpidStr); TestCase.assertEquals(valid, testLong); } @Test public void testToLongMSB() { String dpidStr = "ca:7c:5e:d1:64:7a:95:9b"; long valid = -3856102927509056101L; long testLong = HexString.toLong(dpidStr); TestCase.assertEquals(valid, testLong); } @Test public void testToLongError() { String dpidStr = "09:08:07:06:05:04:03:02:01"; try { HexString.toLong(dpidStr); fail("HexString.toLong() should have thrown a NumberFormatException"); } catch (NumberFormatException expected) { // do nothing } } @Test public void testToStringBytes() { byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 }; String valid = "00:00:00:00:00:00:00:ff"; String testString = HexString.toHexString(dpid); TestCase.assertEquals(valid, testString); } @Test public void testFromHexStringError() { String invalidStr = "00:00:00:00:00:00:ffff"; try { HexString.fromHexString(invalidStr); fail("HexString.fromHexString() should have thrown a NumberFormatException"); } catch (NumberFormatException expected) { // do nothing } } } floodlight-0.90/src/test/java/org/openflow/util/OFTestCase.java0000664000175000017500000000214212041336206025134 0ustar jamespagejamespage/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. **/ package org.openflow.util; import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.OFMessageFactory; import junit.framework.TestCase; public class OFTestCase extends TestCase { public OFMessageFactory messageFactory; @Override protected void setUp() throws Exception { super.setUp(); messageFactory = new BasicFactory(); } public void test() throws Exception { } } floodlight-0.90/floodlight_style_settings.xml0000664000175000017500000007421512041336206022274 0ustar jamespagejamespage floodlight-0.90/apps/0000775000175000017500000000000012041336206015211 5ustar jamespagejamespagefloodlight-0.90/apps/circuitpusher/0000775000175000017500000000000012041336206020102 5ustar jamespagejamespagefloodlight-0.90/apps/circuitpusher/circuitpusher.py0000775000175000017500000002305512041336206023355 0ustar jamespagejamespage#! /usr/bin/python """ circuitpusher utilizes floodlight rest APIs to create a bidirectional circuit, i.e., permanent flow entry, on all switches in route between two devices based on IP addresses with specified priority. Notes: 1. The circuit pusher currently only creates circuit with two IP end points 2. Prior to sending restAPI requests to the circuit pusher, the specified end points must already been known to the controller (i.e., already have sent packets on the network, easy way to assure this is to do a ping (to any target) from the two hosts. 3. The current supported command syntax format is: a) circuitpusher.py --controller={IP}:{rest port} --type ip --src {IP} --dst {IP} --add --name {circuit-name} adds a new circuit between src and dst devices Currently ip circuit is supported. ARP is automatically supported. Currently a simple circuit record storage is provided in a text file circuits.json in the working directory. The file is not protected and does not clean itself between controller restarts. The file is needed for correct operation and the user should make sure deleting the file when floodlight controller is restarted. b) circuitpusher.py --controller={IP}:{rest port} --delete --name {circuit-name} deletes a created circuit (as recorded in circuits.json) using the previously given name @author kcwang """ import os import sys import subprocess import json import argparse import io import time # parse circuit options. Currently supports add and delete actions. # Syntax: # circuitpusher --controller {IP:REST_PORT} --add --name {CIRCUIT_NAME} --type ip --src {IP} --dst {IP} # circuitpusher --controller {IP:REST_PORT} --delete --name {CIRCUIT_NAME} parser = argparse.ArgumentParser(description='Circuit Pusher') parser.add_argument('--controller', dest='controllerRestIp', action='store', default='localhost:8080', help='controller IP:RESTport, e.g., localhost:8080 or A.B.C.D:8080') parser.add_argument('--add', dest='action', action='store_const', const='add', default='add', help='action: add, delete') parser.add_argument('--delete', dest='action', action='store_const', const='delete', default='add', help='action: add, delete') parser.add_argument('--type', dest='type', action='store', default='ip', help='valid types: ip') parser.add_argument('--src', dest='srcAddress', action='store', default='0.0.0.0', help='source address: if type=ip, A.B.C.D') parser.add_argument('--dst', dest='dstAddress', action='store', default='0.0.0.0', help='destination address: if type=ip, A.B.C.D') parser.add_argument('--name', dest='circuitName', action='store', default='circuit-1', help='name for circuit, e.g., circuit-1') args = parser.parse_args() print args controllerRestIp = args.controllerRestIp # first check if a local file exists, which needs to be updated after add/delete if os.path.exists('./circuits.json'): circuitDb = open('./circuits.json','r') lines = circuitDb.readlines() circuitDb.close() else: lines={} if args.action=='add': circuitDb = open('./circuits.json','a') for line in lines: data = json.loads(line) if data['name']==(args.circuitName): print "Circuit %s exists already. Use new name to create." % args.circuitName sys.exit() else: circuitExists = False # retrieve source and destination device attachment points # using DeviceManager rest API command = "curl -s http://%s/wm/device/?ipv4=%s" % (args.controllerRestIp, args.srcAddress) result = os.popen(command).read() parsedResult = json.loads(result) print command+"\n" sourceSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID'] sourcePort = parsedResult[0]['attachmentPoint'][0]['port'] command = "curl -s http://%s/wm/device/?ipv4=%s" % (args.controllerRestIp, args.dstAddress) result = os.popen(command).read() parsedResult = json.loads(result) print command+"\n" destSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID'] destPort = parsedResult[0]['attachmentPoint'][0]['port'] print "Creating circuit:" print "from source device at switch %s port %s" % (sourceSwitch,sourcePort) print "to destination device at switch %s port %s"% (destSwitch,destPort) # retrieving route from source to destination # using Routing rest API command = "curl -s http://%s/wm/topology/route/%s/%s/%s/%s/json" % (controllerRestIp, sourceSwitch, sourcePort, destSwitch, destPort) result = os.popen(command).read() parsedResult = json.loads(result) print command+"\n" print result+"\n" for i in range(len(parsedResult)): if i % 2 == 0: ap1Dpid = parsedResult[i]['switch'] ap1Port = parsedResult[i]['port'] print ap1Dpid, ap1Port else: ap2Dpid = parsedResult[i]['switch'] ap2Port = parsedResult[i]['port'] print ap2Dpid, ap2Port # send one flow mod per pair of APs in route # using StaticFlowPusher rest API # IMPORTANT NOTE: current Floodlight StaticflowEntryPusher # assumes all flow entries to have unique name across all switches # this will most possibly be relaxed later, but for now we # encode each flow entry's name with both switch dpid, user # specified name, and flow type (f: forward, r: reverse, farp/rarp: arp) command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"src-ip\":\"%s\", \"dst-ip\":\"%s\", \"ether-type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress-port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".f", args.srcAddress, args.dstAddress, "0x800", ap1Port, ap2Port, controllerRestIp) result = os.popen(command).read() print command command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"ether-type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress-port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".farp", "0x806", ap1Port, ap2Port, controllerRestIp) result = os.popen(command).read() print command command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"src-ip\":\"%s\", \"dst-ip\":\"%s\", \"ether-type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress-port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".r", args.dstAddress, args.srcAddress, "0x800", ap2Port, ap1Port, controllerRestIp) result = os.popen(command).read() print command command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"ether-type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress-port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".rarp", "0x806", ap2Port, ap1Port, controllerRestIp) result = os.popen(command).read() print command # store created circuit attributes in local ./circuits.json datetime = time.asctime() circuitParams = {'name':args.circuitName, 'Dpid':ap1Dpid, 'inPort':ap1Port, 'outPort':ap2Port, 'datetime':datetime} str = json.dumps(circuitParams) circuitDb.write(str+"\n") # confirm successful circuit creation # using controller rest API command="curl -s http://%s/wm/core/switch/all/flow/json| python -mjson.tool" % (controllerRestIp) result = os.popen(command).read() print command + "\n" + result elif args.action=='delete': circuitDb = open('./circuits.json','w') # removing previously created flow from switches # using StaticFlowPusher rest API # currently, circuitpusher records created circuits in local file ./circuits.db # with circuit name and list of switches circuitExists = False for line in lines: data = json.loads(line) if data['name']==(args.circuitName): circuitExists = True sw = data['Dpid'] print data, sw command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".f", sw, controllerRestIp) result = os.popen(command).read() print command, result command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".farp", sw, controllerRestIp) result = os.popen(command).read() print command, result command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".r", sw, controllerRestIp) result = os.popen(command).read() print command, result command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".rarp", sw, controllerRestIp) result = os.popen(command).read() print command, result else: circuitDb.write(line) circuitDb.close() if not circuitExists: print "specified circuit does not exist" sys.exit() floodlight-0.90/Makefile0000664000175000017500000000065212041336206015711 0ustar jamespagejamespage# Because I am old and crotchety and my fingers can't stop from running # `make` commands .PHONY: docs doc all test tests count install clean all: ant init: ant init docs: ant javadoc doc: ant javadoc javadoc: ant javadoc check: tests test: tests tests: all unit-tests unit-tests: ant tests regression-tests: make -C regress tests count: @find src -name \*.java | xargs wc -l | sort -n clean: ant clean floodlight-0.90/README.txt0000664000175000017500000000054012041336206015743 0ustar jamespagejamespage Floodlight An Apache licensed, Java based OpenFlow controller Floodlight is a Java based OpenFlow controller originally written by David Erickson at Stanford University. It is available under the Apache 2.0 license. For documentation, forums, issue tracking and more visit: http://www.openflowhub.org/display/Floodlight/Floodlight+Home floodlight-0.90/lib/0000775000175000017500000000000012041336206015014 5ustar jamespagejamespagefloodlight-0.90/lib/oro/0000775000175000017500000000000012041336206015613 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/0000775000175000017500000000000012041336206016504 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/net/0000775000175000017500000000000012041336206017272 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/net/floodlightcontroller/0000775000175000017500000000000012041336206023531 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/0000775000175000017500000000000012041336206026543 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/0000775000175000017500000000000012041336206030043 5ustar jamespagejamespagefloodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/Message.java0000664000175000017500000003122312041336206032273 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.EnumMap; import java.util.Set; import java.util.HashSet; import java.util.EnumSet; import java.util.Collections; import java.util.BitSet; import java.nio.ByteBuffer; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("all") public class Message implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Message"); private static final org.apache.thrift.protocol.TField SESSION_IDS_FIELD_DESC = new org.apache.thrift.protocol.TField("sessionIDs", org.apache.thrift.protocol.TType.LIST, (short)1); private static final org.apache.thrift.protocol.TField PACKET_FIELD_DESC = new org.apache.thrift.protocol.TField("packet", org.apache.thrift.protocol.TType.STRUCT, (short)2); public List sessionIDs; // required public Packet packet; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { SESSION_IDS((short)1, "sessionIDs"), PACKET((short)2, "packet"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // SESSION_IDS return SESSION_IDS; case 2: // PACKET return PACKET; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.SESSION_IDS, new org.apache.thrift.meta_data.FieldMetaData("sessionIDs", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)))); tmpMap.put(_Fields.PACKET, new org.apache.thrift.meta_data.FieldMetaData("packet", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Packet.class))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Message.class, metaDataMap); } public Message() { } public Message( List sessionIDs, Packet packet) { this(); this.sessionIDs = sessionIDs; this.packet = packet; } /** * Performs a deep copy on other. */ public Message(Message other) { if (other.isSetSessionIDs()) { List __this__sessionIDs = new ArrayList(); for (String other_element : other.sessionIDs) { __this__sessionIDs.add(other_element); } this.sessionIDs = __this__sessionIDs; } if (other.isSetPacket()) { this.packet = new Packet(other.packet); } } public Message deepCopy() { return new Message(this); } @Override public void clear() { this.sessionIDs = null; this.packet = null; } public int getSessionIDsSize() { return (this.sessionIDs == null) ? 0 : this.sessionIDs.size(); } public java.util.Iterator getSessionIDsIterator() { return (this.sessionIDs == null) ? null : this.sessionIDs.iterator(); } public void addToSessionIDs(String elem) { if (this.sessionIDs == null) { this.sessionIDs = new ArrayList(); } this.sessionIDs.add(elem); } public List getSessionIDs() { return this.sessionIDs; } public Message setSessionIDs(List sessionIDs) { this.sessionIDs = sessionIDs; return this; } public void unsetSessionIDs() { this.sessionIDs = null; } /** Returns true if field sessionIDs is set (has been assigned a value) and false otherwise */ public boolean isSetSessionIDs() { return this.sessionIDs != null; } public void setSessionIDsIsSet(boolean value) { if (!value) { this.sessionIDs = null; } } public Packet getPacket() { return this.packet; } public Message setPacket(Packet packet) { this.packet = packet; return this; } public void unsetPacket() { this.packet = null; } /** Returns true if field packet is set (has been assigned a value) and false otherwise */ public boolean isSetPacket() { return this.packet != null; } public void setPacketIsSet(boolean value) { if (!value) { this.packet = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case SESSION_IDS: if (value == null) { unsetSessionIDs(); } else { setSessionIDs((List)value); } break; case PACKET: if (value == null) { unsetPacket(); } else { setPacket((Packet)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case SESSION_IDS: return getSessionIDs(); case PACKET: return getPacket(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case SESSION_IDS: return isSetSessionIDs(); case PACKET: return isSetPacket(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof Message) return this.equals((Message)that); return false; } public boolean equals(Message that) { if (that == null) return false; boolean this_present_sessionIDs = true && this.isSetSessionIDs(); boolean that_present_sessionIDs = true && that.isSetSessionIDs(); if (this_present_sessionIDs || that_present_sessionIDs) { if (!(this_present_sessionIDs && that_present_sessionIDs)) return false; if (!this.sessionIDs.equals(that.sessionIDs)) return false; } boolean this_present_packet = true && this.isSetPacket(); boolean that_present_packet = true && that.isSetPacket(); if (this_present_packet || that_present_packet) { if (!(this_present_packet && that_present_packet)) return false; if (!this.packet.equals(that.packet)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(Message other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; Message typedOther = (Message)other; lastComparison = Boolean.valueOf(isSetSessionIDs()).compareTo(typedOther.isSetSessionIDs()); if (lastComparison != 0) { return lastComparison; } if (isSetSessionIDs()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.sessionIDs, typedOther.sessionIDs); if (lastComparison != 0) { return lastComparison; } } lastComparison = Boolean.valueOf(isSetPacket()).compareTo(typedOther.isSetPacket()); if (lastComparison != 0) { return lastComparison; } if (isSetPacket()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.packet, typedOther.packet); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // SESSION_IDS if (field.type == org.apache.thrift.protocol.TType.LIST) { { org.apache.thrift.protocol.TList _list0 = iprot.readListBegin(); this.sessionIDs = new ArrayList(_list0.size); for (int _i1 = 0; _i1 < _list0.size; ++_i1) { String _elem2; // required _elem2 = iprot.readString(); this.sessionIDs.add(_elem2); } iprot.readListEnd(); } } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; case 2: // PACKET if (field.type == org.apache.thrift.protocol.TType.STRUCT) { this.packet = new Packet(); this.packet.read(iprot); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.sessionIDs != null) { oprot.writeFieldBegin(SESSION_IDS_FIELD_DESC); { oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, this.sessionIDs.size())); for (String _iter3 : this.sessionIDs) { oprot.writeString(_iter3); } oprot.writeListEnd(); } oprot.writeFieldEnd(); } if (this.packet != null) { oprot.writeFieldBegin(PACKET_FIELD_DESC); this.packet.write(oprot); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("Message("); boolean first = true; sb.append("sessionIDs:"); if (this.sessionIDs == null) { sb.append("null"); } else { sb.append(this.sessionIDs); } first = false; if (!first) sb.append(", "); sb.append("packet:"); if (this.packet == null) { sb.append("null"); } else { sb.append(this.packet); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } floodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/Constants.java0000664000175000017500000000120712041336206032662 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.EnumMap; import java.util.Set; import java.util.HashSet; import java.util.EnumSet; import java.util.Collections; import java.util.BitSet; import java.nio.ByteBuffer; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("all") public class Constants { public static final String VERSION = "0.1.0"; } floodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/SwitchPortTuple.java0000664000175000017500000002650412041336206034035 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.EnumMap; import java.util.Set; import java.util.HashSet; import java.util.EnumSet; import java.util.Collections; import java.util.BitSet; import java.nio.ByteBuffer; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A struct that defines switch port tuple */ @SuppressWarnings("all") public class SwitchPortTuple implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("SwitchPortTuple"); private static final org.apache.thrift.protocol.TField DPID_FIELD_DESC = new org.apache.thrift.protocol.TField("dpid", org.apache.thrift.protocol.TType.I64, (short)1); private static final org.apache.thrift.protocol.TField PORT_FIELD_DESC = new org.apache.thrift.protocol.TField("port", org.apache.thrift.protocol.TType.I16, (short)2); public long dpid; // required public short port; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { DPID((short)1, "dpid"), PORT((short)2, "port"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // DPID return DPID; case 2: // PORT return PORT; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments private static final int __DPID_ISSET_ID = 0; private static final int __PORT_ISSET_ID = 1; private BitSet __isset_bit_vector = new BitSet(2); public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.DPID, new org.apache.thrift.meta_data.FieldMetaData("dpid", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); tmpMap.put(_Fields.PORT, new org.apache.thrift.meta_data.FieldMetaData("port", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I16))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(SwitchPortTuple.class, metaDataMap); } public SwitchPortTuple() { } public SwitchPortTuple( long dpid, short port) { this(); this.dpid = dpid; setDpidIsSet(true); this.port = port; setPortIsSet(true); } /** * Performs a deep copy on other. */ public SwitchPortTuple(SwitchPortTuple other) { __isset_bit_vector.clear(); __isset_bit_vector.or(other.__isset_bit_vector); this.dpid = other.dpid; this.port = other.port; } public SwitchPortTuple deepCopy() { return new SwitchPortTuple(this); } @Override public void clear() { setDpidIsSet(false); this.dpid = 0; setPortIsSet(false); this.port = 0; } public long getDpid() { return this.dpid; } public SwitchPortTuple setDpid(long dpid) { this.dpid = dpid; setDpidIsSet(true); return this; } public void unsetDpid() { __isset_bit_vector.clear(__DPID_ISSET_ID); } /** Returns true if field dpid is set (has been assigned a value) and false otherwise */ public boolean isSetDpid() { return __isset_bit_vector.get(__DPID_ISSET_ID); } public void setDpidIsSet(boolean value) { __isset_bit_vector.set(__DPID_ISSET_ID, value); } public short getPort() { return this.port; } public SwitchPortTuple setPort(short port) { this.port = port; setPortIsSet(true); return this; } public void unsetPort() { __isset_bit_vector.clear(__PORT_ISSET_ID); } /** Returns true if field port is set (has been assigned a value) and false otherwise */ public boolean isSetPort() { return __isset_bit_vector.get(__PORT_ISSET_ID); } public void setPortIsSet(boolean value) { __isset_bit_vector.set(__PORT_ISSET_ID, value); } public void setFieldValue(_Fields field, Object value) { switch (field) { case DPID: if (value == null) { unsetDpid(); } else { setDpid((Long)value); } break; case PORT: if (value == null) { unsetPort(); } else { setPort((Short)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case DPID: return Long.valueOf(getDpid()); case PORT: return Short.valueOf(getPort()); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case DPID: return isSetDpid(); case PORT: return isSetPort(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof SwitchPortTuple) return this.equals((SwitchPortTuple)that); return false; } public boolean equals(SwitchPortTuple that) { if (that == null) return false; boolean this_present_dpid = true; boolean that_present_dpid = true; if (this_present_dpid || that_present_dpid) { if (!(this_present_dpid && that_present_dpid)) return false; if (this.dpid != that.dpid) return false; } boolean this_present_port = true; boolean that_present_port = true; if (this_present_port || that_present_port) { if (!(this_present_port && that_present_port)) return false; if (this.port != that.port) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(SwitchPortTuple other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; SwitchPortTuple typedOther = (SwitchPortTuple)other; lastComparison = Boolean.valueOf(isSetDpid()).compareTo(typedOther.isSetDpid()); if (lastComparison != 0) { return lastComparison; } if (isSetDpid()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.dpid, typedOther.dpid); if (lastComparison != 0) { return lastComparison; } } lastComparison = Boolean.valueOf(isSetPort()).compareTo(typedOther.isSetPort()); if (lastComparison != 0) { return lastComparison; } if (isSetPort()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.port, typedOther.port); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // DPID if (field.type == org.apache.thrift.protocol.TType.I64) { this.dpid = iprot.readI64(); setDpidIsSet(true); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; case 2: // PORT if (field.type == org.apache.thrift.protocol.TType.I16) { this.port = iprot.readI16(); setPortIsSet(true); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); oprot.writeFieldBegin(DPID_FIELD_DESC); oprot.writeI64(this.dpid); oprot.writeFieldEnd(); oprot.writeFieldBegin(PORT_FIELD_DESC); oprot.writeI16(this.port); oprot.writeFieldEnd(); oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("SwitchPortTuple("); boolean first = true; sb.append("dpid:"); sb.append(this.dpid); first = false; if (!first) sb.append(", "); sb.append("port:"); sb.append(this.port); first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. __isset_bit_vector = new BitSet(1); read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } floodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/PacketStreamer.java0000664000175000017500000023266612041336206033637 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.EnumMap; import java.util.Set; import java.util.HashSet; import java.util.EnumSet; import java.util.Collections; import java.util.BitSet; import java.nio.ByteBuffer; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("all") public class PacketStreamer { /** * Packetstreamer API */ public interface Iface { /** * Synchronous method to get packets for a given sessionid * * @param sessionid */ public List getPackets(String sessionid) throws org.apache.thrift.TException; /** * Synchronous method to publish a packet. * It ensure the order that the packets are pushed * * @param packet */ public int pushMessageSync(Message packet) throws org.apache.thrift.TException; /** * Asynchronous method to publish a packet. * Order is not guaranteed. * * @param packet */ public void pushMessageAsync(Message packet) throws org.apache.thrift.TException; /** * Terminate a session * * @param sessionid */ public void terminateSession(String sessionid) throws org.apache.thrift.TException; } public interface AsyncIface { public void getPackets(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; public void pushMessageSync(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; public void pushMessageAsync(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; public void terminateSession(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; } public static class Client extends org.apache.thrift.TServiceClient implements Iface { public static class Factory implements org.apache.thrift.TServiceClientFactory { public Factory() {} public Client getClient(org.apache.thrift.protocol.TProtocol prot) { return new Client(prot); } public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { return new Client(iprot, oprot); } } public Client(org.apache.thrift.protocol.TProtocol prot) { super(prot, prot); } public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { super(iprot, oprot); } public List getPackets(String sessionid) throws org.apache.thrift.TException { send_getPackets(sessionid); return recv_getPackets(); } public void send_getPackets(String sessionid) throws org.apache.thrift.TException { getPackets_args args = new getPackets_args(); args.setSessionid(sessionid); sendBase("getPackets", args); } public List recv_getPackets() throws org.apache.thrift.TException { getPackets_result result = new getPackets_result(); receiveBase(result, "getPackets"); if (result.isSetSuccess()) { return result.success; } throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getPackets failed: unknown result"); } public int pushMessageSync(Message packet) throws org.apache.thrift.TException { send_pushMessageSync(packet); return recv_pushMessageSync(); } public void send_pushMessageSync(Message packet) throws org.apache.thrift.TException { pushMessageSync_args args = new pushMessageSync_args(); args.setPacket(packet); sendBase("pushMessageSync", args); } public int recv_pushMessageSync() throws org.apache.thrift.TException { pushMessageSync_result result = new pushMessageSync_result(); receiveBase(result, "pushMessageSync"); if (result.isSetSuccess()) { return result.success; } throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "pushMessageSync failed: unknown result"); } public void pushMessageAsync(Message packet) throws org.apache.thrift.TException { send_pushMessageAsync(packet); } public void send_pushMessageAsync(Message packet) throws org.apache.thrift.TException { pushMessageAsync_args args = new pushMessageAsync_args(); args.setPacket(packet); sendBase("pushMessageAsync", args); } public void terminateSession(String sessionid) throws org.apache.thrift.TException { send_terminateSession(sessionid); recv_terminateSession(); } public void send_terminateSession(String sessionid) throws org.apache.thrift.TException { terminateSession_args args = new terminateSession_args(); args.setSessionid(sessionid); sendBase("terminateSession", args); } public void recv_terminateSession() throws org.apache.thrift.TException { terminateSession_result result = new terminateSession_result(); receiveBase(result, "terminateSession"); return; } } public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { private org.apache.thrift.async.TAsyncClientManager clientManager; private org.apache.thrift.protocol.TProtocolFactory protocolFactory; public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) { this.clientManager = clientManager; this.protocolFactory = protocolFactory; } public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) { return new AsyncClient(protocolFactory, clientManager, transport); } } public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) { super(protocolFactory, clientManager, transport); } public void getPackets(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); getPackets_call method_call = new getPackets_call(sessionid, resultHandler, this, ___protocolFactory, ___transport); this.___currentMethod = method_call; ___manager.call(method_call); } public static class getPackets_call extends org.apache.thrift.async.TAsyncMethodCall { private String sessionid; public getPackets_call(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { super(client, protocolFactory, transport, resultHandler, false); this.sessionid = sessionid; } public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getPackets", org.apache.thrift.protocol.TMessageType.CALL, 0)); getPackets_args args = new getPackets_args(); args.setSessionid(sessionid); args.write(prot); prot.writeMessageEnd(); } public List getResult() throws org.apache.thrift.TException { if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { throw new IllegalStateException("Method call not finished!"); } org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); return (new Client(prot)).recv_getPackets(); } } public void pushMessageSync(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); pushMessageSync_call method_call = new pushMessageSync_call(packet, resultHandler, this, ___protocolFactory, ___transport); this.___currentMethod = method_call; ___manager.call(method_call); } public static class pushMessageSync_call extends org.apache.thrift.async.TAsyncMethodCall { private Message packet; public pushMessageSync_call(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { super(client, protocolFactory, transport, resultHandler, false); this.packet = packet; } public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("pushMessageSync", org.apache.thrift.protocol.TMessageType.CALL, 0)); pushMessageSync_args args = new pushMessageSync_args(); args.setPacket(packet); args.write(prot); prot.writeMessageEnd(); } public int getResult() throws org.apache.thrift.TException { if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { throw new IllegalStateException("Method call not finished!"); } org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); return (new Client(prot)).recv_pushMessageSync(); } } public void pushMessageAsync(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); pushMessageAsync_call method_call = new pushMessageAsync_call(packet, resultHandler, this, ___protocolFactory, ___transport); this.___currentMethod = method_call; ___manager.call(method_call); } public static class pushMessageAsync_call extends org.apache.thrift.async.TAsyncMethodCall { private Message packet; public pushMessageAsync_call(Message packet, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { super(client, protocolFactory, transport, resultHandler, true); this.packet = packet; } public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("pushMessageAsync", org.apache.thrift.protocol.TMessageType.CALL, 0)); pushMessageAsync_args args = new pushMessageAsync_args(); args.setPacket(packet); args.write(prot); prot.writeMessageEnd(); } public void getResult() throws org.apache.thrift.TException { if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { throw new IllegalStateException("Method call not finished!"); } org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); } } public void terminateSession(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); terminateSession_call method_call = new terminateSession_call(sessionid, resultHandler, this, ___protocolFactory, ___transport); this.___currentMethod = method_call; ___manager.call(method_call); } public static class terminateSession_call extends org.apache.thrift.async.TAsyncMethodCall { private String sessionid; public terminateSession_call(String sessionid, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { super(client, protocolFactory, transport, resultHandler, false); this.sessionid = sessionid; } public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("terminateSession", org.apache.thrift.protocol.TMessageType.CALL, 0)); terminateSession_args args = new terminateSession_args(); args.setSessionid(sessionid); args.write(prot); prot.writeMessageEnd(); } public void getResult() throws org.apache.thrift.TException { if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { throw new IllegalStateException("Method call not finished!"); } org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); (new Client(prot)).recv_terminateSession(); } } } public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName()); public Processor(I iface) { super(iface, getProcessMap(new HashMap>())); } protected Processor(I iface, Map> processMap) { super(iface, getProcessMap(processMap)); } private static Map> getProcessMap(Map> processMap) { processMap.put("getPackets", new getPackets()); processMap.put("pushMessageSync", new pushMessageSync()); processMap.put("pushMessageAsync", new pushMessageAsync()); processMap.put("terminateSession", new terminateSession()); return processMap; } private static class getPackets extends org.apache.thrift.ProcessFunction { public getPackets() { super("getPackets"); } protected getPackets_args getEmptyArgsInstance() { return new getPackets_args(); } protected getPackets_result getResult(I iface, getPackets_args args) throws org.apache.thrift.TException { getPackets_result result = new getPackets_result(); result.success = iface.getPackets(args.sessionid); return result; } } private static class pushMessageSync extends org.apache.thrift.ProcessFunction { public pushMessageSync() { super("pushMessageSync"); } protected pushMessageSync_args getEmptyArgsInstance() { return new pushMessageSync_args(); } protected pushMessageSync_result getResult(I iface, pushMessageSync_args args) throws org.apache.thrift.TException { pushMessageSync_result result = new pushMessageSync_result(); result.success = iface.pushMessageSync(args.packet); result.setSuccessIsSet(true); return result; } } private static class pushMessageAsync extends org.apache.thrift.ProcessFunction { public pushMessageAsync() { super("pushMessageAsync"); } protected pushMessageAsync_args getEmptyArgsInstance() { return new pushMessageAsync_args(); } protected org.apache.thrift.TBase getResult(I iface, pushMessageAsync_args args) throws org.apache.thrift.TException { iface.pushMessageAsync(args.packet); return null; } } private static class terminateSession extends org.apache.thrift.ProcessFunction { public terminateSession() { super("terminateSession"); } protected terminateSession_args getEmptyArgsInstance() { return new terminateSession_args(); } protected terminateSession_result getResult(I iface, terminateSession_args args) throws org.apache.thrift.TException { terminateSession_result result = new terminateSession_result(); iface.terminateSession(args.sessionid); return result; } } } public static class getPackets_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("getPackets_args"); private static final org.apache.thrift.protocol.TField SESSIONID_FIELD_DESC = new org.apache.thrift.protocol.TField("sessionid", org.apache.thrift.protocol.TType.STRING, (short)1); public String sessionid; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { SESSIONID((short)1, "sessionid"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // SESSIONID return SESSIONID; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.SESSIONID, new org.apache.thrift.meta_data.FieldMetaData("sessionid", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(getPackets_args.class, metaDataMap); } public getPackets_args() { } public getPackets_args( String sessionid) { this(); this.sessionid = sessionid; } /** * Performs a deep copy on other. */ public getPackets_args(getPackets_args other) { if (other.isSetSessionid()) { this.sessionid = other.sessionid; } } public getPackets_args deepCopy() { return new getPackets_args(this); } @Override public void clear() { this.sessionid = null; } public String getSessionid() { return this.sessionid; } public getPackets_args setSessionid(String sessionid) { this.sessionid = sessionid; return this; } public void unsetSessionid() { this.sessionid = null; } /** Returns true if field sessionid is set (has been assigned a value) and false otherwise */ public boolean isSetSessionid() { return this.sessionid != null; } public void setSessionidIsSet(boolean value) { if (!value) { this.sessionid = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case SESSIONID: if (value == null) { unsetSessionid(); } else { setSessionid((String)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case SESSIONID: return getSessionid(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case SESSIONID: return isSetSessionid(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof getPackets_args) return this.equals((getPackets_args)that); return false; } public boolean equals(getPackets_args that) { if (that == null) return false; boolean this_present_sessionid = true && this.isSetSessionid(); boolean that_present_sessionid = true && that.isSetSessionid(); if (this_present_sessionid || that_present_sessionid) { if (!(this_present_sessionid && that_present_sessionid)) return false; if (!this.sessionid.equals(that.sessionid)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(getPackets_args other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; getPackets_args typedOther = (getPackets_args)other; lastComparison = Boolean.valueOf(isSetSessionid()).compareTo(typedOther.isSetSessionid()); if (lastComparison != 0) { return lastComparison; } if (isSetSessionid()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.sessionid, typedOther.sessionid); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // SESSIONID if (field.type == org.apache.thrift.protocol.TType.STRING) { this.sessionid = iprot.readString(); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.sessionid != null) { oprot.writeFieldBegin(SESSIONID_FIELD_DESC); oprot.writeString(this.sessionid); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("getPackets_args("); boolean first = true; sb.append("sessionid:"); if (this.sessionid == null) { sb.append("null"); } else { sb.append(this.sessionid); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class getPackets_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("getPackets_result"); private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.LIST, (short)0); public List success; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { SUCCESS((short)0, "success"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 0: // SUCCESS return SUCCESS; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true)))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(getPackets_result.class, metaDataMap); } public getPackets_result() { } public getPackets_result( List success) { this(); this.success = success; } /** * Performs a deep copy on other. */ public getPackets_result(getPackets_result other) { if (other.isSetSuccess()) { List __this__success = new ArrayList(); for (ByteBuffer other_element : other.success) { ByteBuffer temp_binary_element = org.apache.thrift.TBaseHelper.copyBinary(other_element); ; __this__success.add(temp_binary_element); } this.success = __this__success; } } public getPackets_result deepCopy() { return new getPackets_result(this); } @Override public void clear() { this.success = null; } public int getSuccessSize() { return (this.success == null) ? 0 : this.success.size(); } public java.util.Iterator getSuccessIterator() { return (this.success == null) ? null : this.success.iterator(); } public void addToSuccess(ByteBuffer elem) { if (this.success == null) { this.success = new ArrayList(); } this.success.add(elem); } public List getSuccess() { return this.success; } public getPackets_result setSuccess(List success) { this.success = success; return this; } public void unsetSuccess() { this.success = null; } /** Returns true if field success is set (has been assigned a value) and false otherwise */ public boolean isSetSuccess() { return this.success != null; } public void setSuccessIsSet(boolean value) { if (!value) { this.success = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case SUCCESS: if (value == null) { unsetSuccess(); } else { setSuccess((List)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case SUCCESS: return getSuccess(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case SUCCESS: return isSetSuccess(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof getPackets_result) return this.equals((getPackets_result)that); return false; } public boolean equals(getPackets_result that) { if (that == null) return false; boolean this_present_success = true && this.isSetSuccess(); boolean that_present_success = true && that.isSetSuccess(); if (this_present_success || that_present_success) { if (!(this_present_success && that_present_success)) return false; if (!this.success.equals(that.success)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(getPackets_result other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; getPackets_result typedOther = (getPackets_result)other; lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(typedOther.isSetSuccess()); if (lastComparison != 0) { return lastComparison; } if (isSetSuccess()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, typedOther.success); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 0: // SUCCESS if (field.type == org.apache.thrift.protocol.TType.LIST) { { org.apache.thrift.protocol.TList _list4 = iprot.readListBegin(); this.success = new ArrayList(_list4.size); for (int _i5 = 0; _i5 < _list4.size; ++_i5) { ByteBuffer _elem6; // required _elem6 = iprot.readBinary(); this.success.add(_elem6); } iprot.readListEnd(); } } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { oprot.writeStructBegin(STRUCT_DESC); if (this.isSetSuccess()) { oprot.writeFieldBegin(SUCCESS_FIELD_DESC); { oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, this.success.size())); for (ByteBuffer _iter7 : this.success) { oprot.writeBinary(_iter7); } oprot.writeListEnd(); } oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("getPackets_result("); boolean first = true; sb.append("success:"); if (this.success == null) { sb.append("null"); } else { sb.append(this.success); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class pushMessageSync_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("pushMessageSync_args"); private static final org.apache.thrift.protocol.TField PACKET_FIELD_DESC = new org.apache.thrift.protocol.TField("packet", org.apache.thrift.protocol.TType.STRUCT, (short)1); public Message packet; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { PACKET((short)1, "packet"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // PACKET return PACKET; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.PACKET, new org.apache.thrift.meta_data.FieldMetaData("packet", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Message.class))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(pushMessageSync_args.class, metaDataMap); } public pushMessageSync_args() { } public pushMessageSync_args( Message packet) { this(); this.packet = packet; } /** * Performs a deep copy on other. */ public pushMessageSync_args(pushMessageSync_args other) { if (other.isSetPacket()) { this.packet = new Message(other.packet); } } public pushMessageSync_args deepCopy() { return new pushMessageSync_args(this); } @Override public void clear() { this.packet = null; } public Message getPacket() { return this.packet; } public pushMessageSync_args setPacket(Message packet) { this.packet = packet; return this; } public void unsetPacket() { this.packet = null; } /** Returns true if field packet is set (has been assigned a value) and false otherwise */ public boolean isSetPacket() { return this.packet != null; } public void setPacketIsSet(boolean value) { if (!value) { this.packet = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case PACKET: if (value == null) { unsetPacket(); } else { setPacket((Message)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case PACKET: return getPacket(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case PACKET: return isSetPacket(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof pushMessageSync_args) return this.equals((pushMessageSync_args)that); return false; } public boolean equals(pushMessageSync_args that) { if (that == null) return false; boolean this_present_packet = true && this.isSetPacket(); boolean that_present_packet = true && that.isSetPacket(); if (this_present_packet || that_present_packet) { if (!(this_present_packet && that_present_packet)) return false; if (!this.packet.equals(that.packet)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(pushMessageSync_args other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; pushMessageSync_args typedOther = (pushMessageSync_args)other; lastComparison = Boolean.valueOf(isSetPacket()).compareTo(typedOther.isSetPacket()); if (lastComparison != 0) { return lastComparison; } if (isSetPacket()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.packet, typedOther.packet); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // PACKET if (field.type == org.apache.thrift.protocol.TType.STRUCT) { this.packet = new Message(); this.packet.read(iprot); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.packet != null) { oprot.writeFieldBegin(PACKET_FIELD_DESC); this.packet.write(oprot); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("pushMessageSync_args("); boolean first = true; sb.append("packet:"); if (this.packet == null) { sb.append("null"); } else { sb.append(this.packet); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class pushMessageSync_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("pushMessageSync_result"); private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.I32, (short)0); public int success; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { SUCCESS((short)0, "success"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 0: // SUCCESS return SUCCESS; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments private static final int __SUCCESS_ISSET_ID = 0; private BitSet __isset_bit_vector = new BitSet(1); public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(pushMessageSync_result.class, metaDataMap); } public pushMessageSync_result() { } public pushMessageSync_result( int success) { this(); this.success = success; setSuccessIsSet(true); } /** * Performs a deep copy on other. */ public pushMessageSync_result(pushMessageSync_result other) { __isset_bit_vector.clear(); __isset_bit_vector.or(other.__isset_bit_vector); this.success = other.success; } public pushMessageSync_result deepCopy() { return new pushMessageSync_result(this); } @Override public void clear() { setSuccessIsSet(false); this.success = 0; } public int getSuccess() { return this.success; } public pushMessageSync_result setSuccess(int success) { this.success = success; setSuccessIsSet(true); return this; } public void unsetSuccess() { __isset_bit_vector.clear(__SUCCESS_ISSET_ID); } /** Returns true if field success is set (has been assigned a value) and false otherwise */ public boolean isSetSuccess() { return __isset_bit_vector.get(__SUCCESS_ISSET_ID); } public void setSuccessIsSet(boolean value) { __isset_bit_vector.set(__SUCCESS_ISSET_ID, value); } public void setFieldValue(_Fields field, Object value) { switch (field) { case SUCCESS: if (value == null) { unsetSuccess(); } else { setSuccess((Integer)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case SUCCESS: return Integer.valueOf(getSuccess()); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case SUCCESS: return isSetSuccess(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof pushMessageSync_result) return this.equals((pushMessageSync_result)that); return false; } public boolean equals(pushMessageSync_result that) { if (that == null) return false; boolean this_present_success = true; boolean that_present_success = true; if (this_present_success || that_present_success) { if (!(this_present_success && that_present_success)) return false; if (this.success != that.success) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(pushMessageSync_result other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; pushMessageSync_result typedOther = (pushMessageSync_result)other; lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(typedOther.isSetSuccess()); if (lastComparison != 0) { return lastComparison; } if (isSetSuccess()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, typedOther.success); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 0: // SUCCESS if (field.type == org.apache.thrift.protocol.TType.I32) { this.success = iprot.readI32(); setSuccessIsSet(true); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { oprot.writeStructBegin(STRUCT_DESC); if (this.isSetSuccess()) { oprot.writeFieldBegin(SUCCESS_FIELD_DESC); oprot.writeI32(this.success); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("pushMessageSync_result("); boolean first = true; sb.append("success:"); sb.append(this.success); first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. __isset_bit_vector = new BitSet(1); read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class pushMessageAsync_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("pushMessageAsync_args"); private static final org.apache.thrift.protocol.TField PACKET_FIELD_DESC = new org.apache.thrift.protocol.TField("packet", org.apache.thrift.protocol.TType.STRUCT, (short)1); public Message packet; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { PACKET((short)1, "packet"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // PACKET return PACKET; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.PACKET, new org.apache.thrift.meta_data.FieldMetaData("packet", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Message.class))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(pushMessageAsync_args.class, metaDataMap); } public pushMessageAsync_args() { } public pushMessageAsync_args( Message packet) { this(); this.packet = packet; } /** * Performs a deep copy on other. */ public pushMessageAsync_args(pushMessageAsync_args other) { if (other.isSetPacket()) { this.packet = new Message(other.packet); } } public pushMessageAsync_args deepCopy() { return new pushMessageAsync_args(this); } @Override public void clear() { this.packet = null; } public Message getPacket() { return this.packet; } public pushMessageAsync_args setPacket(Message packet) { this.packet = packet; return this; } public void unsetPacket() { this.packet = null; } /** Returns true if field packet is set (has been assigned a value) and false otherwise */ public boolean isSetPacket() { return this.packet != null; } public void setPacketIsSet(boolean value) { if (!value) { this.packet = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case PACKET: if (value == null) { unsetPacket(); } else { setPacket((Message)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case PACKET: return getPacket(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case PACKET: return isSetPacket(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof pushMessageAsync_args) return this.equals((pushMessageAsync_args)that); return false; } public boolean equals(pushMessageAsync_args that) { if (that == null) return false; boolean this_present_packet = true && this.isSetPacket(); boolean that_present_packet = true && that.isSetPacket(); if (this_present_packet || that_present_packet) { if (!(this_present_packet && that_present_packet)) return false; if (!this.packet.equals(that.packet)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(pushMessageAsync_args other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; pushMessageAsync_args typedOther = (pushMessageAsync_args)other; lastComparison = Boolean.valueOf(isSetPacket()).compareTo(typedOther.isSetPacket()); if (lastComparison != 0) { return lastComparison; } if (isSetPacket()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.packet, typedOther.packet); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // PACKET if (field.type == org.apache.thrift.protocol.TType.STRUCT) { this.packet = new Message(); this.packet.read(iprot); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.packet != null) { oprot.writeFieldBegin(PACKET_FIELD_DESC); this.packet.write(oprot); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("pushMessageAsync_args("); boolean first = true; sb.append("packet:"); if (this.packet == null) { sb.append("null"); } else { sb.append(this.packet); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class terminateSession_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("terminateSession_args"); private static final org.apache.thrift.protocol.TField SESSIONID_FIELD_DESC = new org.apache.thrift.protocol.TField("sessionid", org.apache.thrift.protocol.TType.STRING, (short)1); public String sessionid; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { SESSIONID((short)1, "sessionid"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // SESSIONID return SESSIONID; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.SESSIONID, new org.apache.thrift.meta_data.FieldMetaData("sessionid", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(terminateSession_args.class, metaDataMap); } public terminateSession_args() { } public terminateSession_args( String sessionid) { this(); this.sessionid = sessionid; } /** * Performs a deep copy on other. */ public terminateSession_args(terminateSession_args other) { if (other.isSetSessionid()) { this.sessionid = other.sessionid; } } public terminateSession_args deepCopy() { return new terminateSession_args(this); } @Override public void clear() { this.sessionid = null; } public String getSessionid() { return this.sessionid; } public terminateSession_args setSessionid(String sessionid) { this.sessionid = sessionid; return this; } public void unsetSessionid() { this.sessionid = null; } /** Returns true if field sessionid is set (has been assigned a value) and false otherwise */ public boolean isSetSessionid() { return this.sessionid != null; } public void setSessionidIsSet(boolean value) { if (!value) { this.sessionid = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case SESSIONID: if (value == null) { unsetSessionid(); } else { setSessionid((String)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case SESSIONID: return getSessionid(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case SESSIONID: return isSetSessionid(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof terminateSession_args) return this.equals((terminateSession_args)that); return false; } public boolean equals(terminateSession_args that) { if (that == null) return false; boolean this_present_sessionid = true && this.isSetSessionid(); boolean that_present_sessionid = true && that.isSetSessionid(); if (this_present_sessionid || that_present_sessionid) { if (!(this_present_sessionid && that_present_sessionid)) return false; if (!this.sessionid.equals(that.sessionid)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(terminateSession_args other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; terminateSession_args typedOther = (terminateSession_args)other; lastComparison = Boolean.valueOf(isSetSessionid()).compareTo(typedOther.isSetSessionid()); if (lastComparison != 0) { return lastComparison; } if (isSetSessionid()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.sessionid, typedOther.sessionid); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // SESSIONID if (field.type == org.apache.thrift.protocol.TType.STRING) { this.sessionid = iprot.readString(); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.sessionid != null) { oprot.writeFieldBegin(SESSIONID_FIELD_DESC); oprot.writeString(this.sessionid); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("terminateSession_args("); boolean first = true; sb.append("sessionid:"); if (this.sessionid == null) { sb.append("null"); } else { sb.append(this.sessionid); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } public static class terminateSession_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("terminateSession_result"); /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { ; private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(terminateSession_result.class, metaDataMap); } public terminateSession_result() { } /** * Performs a deep copy on other. */ public terminateSession_result(terminateSession_result other) { } public terminateSession_result deepCopy() { return new terminateSession_result(this); } @Override public void clear() { } public void setFieldValue(_Fields field, Object value) { switch (field) { } } public Object getFieldValue(_Fields field) { switch (field) { } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof terminateSession_result) return this.equals((terminateSession_result)that); return false; } public boolean equals(terminateSession_result that) { if (that == null) return false; return true; } @Override public int hashCode() { return 0; } public int compareTo(terminateSession_result other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; terminateSession_result typedOther = (terminateSession_result)other; return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { oprot.writeStructBegin(STRUCT_DESC); oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("terminateSession_result("); boolean first = true; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } } floodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/Packet.java0000664000175000017500000003556012041336206032126 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.EnumMap; import java.util.Set; import java.util.HashSet; import java.util.EnumSet; import java.util.Collections; import java.util.BitSet; import java.nio.ByteBuffer; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("all") public class Packet implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Packet"); private static final org.apache.thrift.protocol.TField MESSAGE_TYPE_FIELD_DESC = new org.apache.thrift.protocol.TField("messageType", org.apache.thrift.protocol.TType.I32, (short)1); private static final org.apache.thrift.protocol.TField SW_PORT_TUPLE_FIELD_DESC = new org.apache.thrift.protocol.TField("swPortTuple", org.apache.thrift.protocol.TType.STRUCT, (short)2); private static final org.apache.thrift.protocol.TField DATA_FIELD_DESC = new org.apache.thrift.protocol.TField("data", org.apache.thrift.protocol.TType.STRING, (short)3); /** * * @see OFMessageType */ public OFMessageType messageType; // required public SwitchPortTuple swPortTuple; // required public ByteBuffer data; // required /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { /** * * @see OFMessageType */ MESSAGE_TYPE((short)1, "messageType"), SW_PORT_TUPLE((short)2, "swPortTuple"), DATA((short)3, "data"); private static final Map byName = new HashMap(); static { for (_Fields field : EnumSet.allOf(_Fields.class)) { byName.put(field.getFieldName(), field); } } /** * Find the _Fields constant that matches fieldId, or null if its not found. */ public static _Fields findByThriftId(int fieldId) { switch(fieldId) { case 1: // MESSAGE_TYPE return MESSAGE_TYPE; case 2: // SW_PORT_TUPLE return SW_PORT_TUPLE; case 3: // DATA return DATA; default: return null; } } /** * Find the _Fields constant that matches fieldId, throwing an exception * if it is not found. */ public static _Fields findByThriftIdOrThrow(int fieldId) { _Fields fields = findByThriftId(fieldId); if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); return fields; } /** * Find the _Fields constant that matches name, or null if its not found. */ public static _Fields findByName(String name) { return byName.get(name); } private final short _thriftId; private final String _fieldName; _Fields(short thriftId, String fieldName) { _thriftId = thriftId; _fieldName = fieldName; } public short getThriftFieldId() { return _thriftId; } public String getFieldName() { return _fieldName; } } // isset id assignments public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.MESSAGE_TYPE, new org.apache.thrift.meta_data.FieldMetaData("messageType", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, OFMessageType.class))); tmpMap.put(_Fields.SW_PORT_TUPLE, new org.apache.thrift.meta_data.FieldMetaData("swPortTuple", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, SwitchPortTuple.class))); tmpMap.put(_Fields.DATA, new org.apache.thrift.meta_data.FieldMetaData("data", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , true))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Packet.class, metaDataMap); } public Packet() { } public Packet( OFMessageType messageType, SwitchPortTuple swPortTuple, ByteBuffer data) { this(); this.messageType = messageType; this.swPortTuple = swPortTuple; this.data = data; } /** * Performs a deep copy on other. */ public Packet(Packet other) { if (other.isSetMessageType()) { this.messageType = other.messageType; } if (other.isSetSwPortTuple()) { this.swPortTuple = new SwitchPortTuple(other.swPortTuple); } if (other.isSetData()) { this.data = org.apache.thrift.TBaseHelper.copyBinary(other.data); ; } } public Packet deepCopy() { return new Packet(this); } @Override public void clear() { this.messageType = null; this.swPortTuple = null; this.data = null; } /** * * @see OFMessageType */ public OFMessageType getMessageType() { return this.messageType; } /** * * @see OFMessageType */ public Packet setMessageType(OFMessageType messageType) { this.messageType = messageType; return this; } public void unsetMessageType() { this.messageType = null; } /** Returns true if field messageType is set (has been assigned a value) and false otherwise */ public boolean isSetMessageType() { return this.messageType != null; } public void setMessageTypeIsSet(boolean value) { if (!value) { this.messageType = null; } } public SwitchPortTuple getSwPortTuple() { return this.swPortTuple; } public Packet setSwPortTuple(SwitchPortTuple swPortTuple) { this.swPortTuple = swPortTuple; return this; } public void unsetSwPortTuple() { this.swPortTuple = null; } /** Returns true if field swPortTuple is set (has been assigned a value) and false otherwise */ public boolean isSetSwPortTuple() { return this.swPortTuple != null; } public void setSwPortTupleIsSet(boolean value) { if (!value) { this.swPortTuple = null; } } public byte[] getData() { setData(org.apache.thrift.TBaseHelper.rightSize(data)); return data == null ? null : data.array(); } public ByteBuffer bufferForData() { return data; } public Packet setData(byte[] data) { setData(data == null ? (ByteBuffer)null : ByteBuffer.wrap(data)); return this; } public Packet setData(ByteBuffer data) { this.data = data; return this; } public void unsetData() { this.data = null; } /** Returns true if field data is set (has been assigned a value) and false otherwise */ public boolean isSetData() { return this.data != null; } public void setDataIsSet(boolean value) { if (!value) { this.data = null; } } public void setFieldValue(_Fields field, Object value) { switch (field) { case MESSAGE_TYPE: if (value == null) { unsetMessageType(); } else { setMessageType((OFMessageType)value); } break; case SW_PORT_TUPLE: if (value == null) { unsetSwPortTuple(); } else { setSwPortTuple((SwitchPortTuple)value); } break; case DATA: if (value == null) { unsetData(); } else { setData((ByteBuffer)value); } break; } } public Object getFieldValue(_Fields field) { switch (field) { case MESSAGE_TYPE: return getMessageType(); case SW_PORT_TUPLE: return getSwPortTuple(); case DATA: return getData(); } throw new IllegalStateException(); } /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); } switch (field) { case MESSAGE_TYPE: return isSetMessageType(); case SW_PORT_TUPLE: return isSetSwPortTuple(); case DATA: return isSetData(); } throw new IllegalStateException(); } @Override public boolean equals(Object that) { if (that == null) return false; if (that instanceof Packet) return this.equals((Packet)that); return false; } public boolean equals(Packet that) { if (that == null) return false; boolean this_present_messageType = true && this.isSetMessageType(); boolean that_present_messageType = true && that.isSetMessageType(); if (this_present_messageType || that_present_messageType) { if (!(this_present_messageType && that_present_messageType)) return false; if (!this.messageType.equals(that.messageType)) return false; } boolean this_present_swPortTuple = true && this.isSetSwPortTuple(); boolean that_present_swPortTuple = true && that.isSetSwPortTuple(); if (this_present_swPortTuple || that_present_swPortTuple) { if (!(this_present_swPortTuple && that_present_swPortTuple)) return false; if (!this.swPortTuple.equals(that.swPortTuple)) return false; } boolean this_present_data = true && this.isSetData(); boolean that_present_data = true && that.isSetData(); if (this_present_data || that_present_data) { if (!(this_present_data && that_present_data)) return false; if (!this.data.equals(that.data)) return false; } return true; } @Override public int hashCode() { return 0; } public int compareTo(Packet other) { if (!getClass().equals(other.getClass())) { return getClass().getName().compareTo(other.getClass().getName()); } int lastComparison = 0; Packet typedOther = (Packet)other; lastComparison = Boolean.valueOf(isSetMessageType()).compareTo(typedOther.isSetMessageType()); if (lastComparison != 0) { return lastComparison; } if (isSetMessageType()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.messageType, typedOther.messageType); if (lastComparison != 0) { return lastComparison; } } lastComparison = Boolean.valueOf(isSetSwPortTuple()).compareTo(typedOther.isSetSwPortTuple()); if (lastComparison != 0) { return lastComparison; } if (isSetSwPortTuple()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.swPortTuple, typedOther.swPortTuple); if (lastComparison != 0) { return lastComparison; } } lastComparison = Boolean.valueOf(isSetData()).compareTo(typedOther.isSetData()); if (lastComparison != 0) { return lastComparison; } if (isSetData()) { lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.data, typedOther.data); if (lastComparison != 0) { return lastComparison; } } return 0; } public _Fields fieldForId(int fieldId) { return _Fields.findByThriftId(fieldId); } public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { org.apache.thrift.protocol.TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); if (field.type == org.apache.thrift.protocol.TType.STOP) { break; } switch (field.id) { case 1: // MESSAGE_TYPE if (field.type == org.apache.thrift.protocol.TType.I32) { this.messageType = OFMessageType.findByValue(iprot.readI32()); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; case 2: // SW_PORT_TUPLE if (field.type == org.apache.thrift.protocol.TType.STRUCT) { this.swPortTuple = new SwitchPortTuple(); this.swPortTuple.read(iprot); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; case 3: // DATA if (field.type == org.apache.thrift.protocol.TType.STRING) { this.data = iprot.readBinary(); } else { org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } iprot.readStructEnd(); // check for required fields of primitive type, which can't be checked in the validate method validate(); } public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { validate(); oprot.writeStructBegin(STRUCT_DESC); if (this.messageType != null) { oprot.writeFieldBegin(MESSAGE_TYPE_FIELD_DESC); oprot.writeI32(this.messageType.getValue()); oprot.writeFieldEnd(); } if (this.swPortTuple != null) { oprot.writeFieldBegin(SW_PORT_TUPLE_FIELD_DESC); this.swPortTuple.write(oprot); oprot.writeFieldEnd(); } if (this.data != null) { oprot.writeFieldBegin(DATA_FIELD_DESC); oprot.writeBinary(this.data); oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); } @Override public String toString() { StringBuilder sb = new StringBuilder("Packet("); boolean first = true; sb.append("messageType:"); if (this.messageType == null) { sb.append("null"); } else { sb.append(this.messageType); } first = false; if (!first) sb.append(", "); sb.append("swPortTuple:"); if (this.swPortTuple == null) { sb.append("null"); } else { sb.append(this.swPortTuple); } first = false; if (!first) sb.append(", "); sb.append("data:"); if (this.data == null) { sb.append("null"); } else { org.apache.thrift.TBaseHelper.toString(this.data, sb); } first = false; sb.append(")"); return sb.toString(); } public void validate() throws org.apache.thrift.TException { // check for required fields } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { try { write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { try { read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); } catch (org.apache.thrift.TException te) { throw new java.io.IOException(te); } } } floodlight-0.90/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/OFMessageType.java0000664000175000017500000000406112041336206033362 0ustar jamespagejamespage/** * Autogenerated by Thrift Compiler (0.7.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING */ package net.floodlightcontroller.packetstreamer.thrift; import java.util.Map; import java.util.HashMap; import org.apache.thrift.TEnum; /** * OFMessage type * */ @SuppressWarnings("all") public enum OFMessageType implements org.apache.thrift.TEnum { HELLO(0), ERROR(1), ECHO_REQUEST(2), ECHO_REPLY(3), VENDOR(4), FEATURES_REQUEST(5), FEATURES_REPLY(6), GET_CONFIG_REQUEST(7), GET_CONFIG_REPLY(8), SET_CONFIG(9), PACKET_IN(10), FLOW_REMOVED(11), PORT_STATUS(12), PACKET_OUT(13), FLOW_MOD(14), PORT_MOD(15), STATS_REQUEST(16), STATS_REPLY(17), BARRIER_REQUEST(18), BARRIER_REPLY(19); private final int value; private OFMessageType(int value) { this.value = value; } /** * Get the integer value of this enum value, as defined in the Thrift IDL. */ public int getValue() { return value; } /** * Find a the enum type by its integer value, as defined in the Thrift IDL. * @return null if the value is not found. */ public static OFMessageType findByValue(int value) { switch (value) { case 0: return HELLO; case 1: return ERROR; case 2: return ECHO_REQUEST; case 3: return ECHO_REPLY; case 4: return VENDOR; case 5: return FEATURES_REQUEST; case 6: return FEATURES_REPLY; case 7: return GET_CONFIG_REQUEST; case 8: return GET_CONFIG_REPLY; case 9: return SET_CONFIG; case 10: return PACKET_IN; case 11: return FLOW_REMOVED; case 12: return PORT_STATUS; case 13: return PACKET_OUT; case 14: return FLOW_MOD; case 15: return PORT_MOD; case 16: return STATS_REQUEST; case 17: return STATS_REPLY; case 18: return BARRIER_REQUEST; case 19: return BARRIER_REPLY; default: return null; } } } floodlight-0.90/floodlight.sh0000775000175000017500000000241412041336206016741 0ustar jamespagejamespage#!/bin/sh # Set paths FL_HOME=`dirname $0` FL_JAR="${FL_HOME}/target/floodlight.jar" FL_LOGBACK="${FL_HOME}/logback.xml" # Set JVM options JVM_OPTS="" JVM_OPTS="$JVM_OPTS -server -d64" JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m" JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods" JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192" JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8" JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false" # Create a logback file if required [ -f ${FL_LOGBACK} ] || cat <${FL_LOGBACK} %level [%logger:%thread] %msg%n EOF_LOGBACK echo "Starting floodlight server ..." java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -jar ${FL_JAR} floodlight-0.90/NOTICE.txt0000664000175000017500000000141412041336206015770 0ustar jamespagejamespageINDEMNITY AND DISCLAIMER OF WARRANTIES SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27973/00100/SF/5339045.1 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. floodlight-0.90/build.xml0000664000175000017500000002532312041336206016074 0ustar jamespagejamespage floodlight-0.90/logback.xml0000664000175000017500000000100312041336206016364 0ustar jamespagejamespage %level [%logger:%thread] %msg%n floodlight-0.90/example/0000775000175000017500000000000012041336206015701 5ustar jamespagejamespagefloodlight-0.90/example/packetStreamerClientExample.py0000775000175000017500000000746512041336206023717 0ustar jamespagejamespage#!/usr/bin/python import urllib2 import json import re import sys from optparse import OptionParser sys.path.append('~/floodlight/target/gen-py') sys.path.append('~/floodlight/thrift/lib/py') from packetstreamer import PacketStreamer from packetstreamer.ttypes import * from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol SESSIONID = 'sessionId' usage = "usage: %prog [options]" parser = OptionParser(usage=usage, version="%prog 1.0") parser.add_option("-c", "--controller", dest="controller", metavar="CONTROLLER_IP", default="127.0.0.1", help="controller's IP address") parser.add_option("-m", "--mac", dest="mac", metavar="HOST_MAC", help="The host mac address to trace the OF packets") (options, args) = parser.parse_args() def validateIp(ip): ipReg = ("(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" "\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" "\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" "\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") m = re.compile(ipReg).match(ip) if m: return True else : return False def validateMac(mac): macReg = '([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}' # same regex as above m = re.compile(macReg).match(mac) if m: return True else : return False if not validateIp(options.controller): parser.error("Invalid format for ip address.") if not options.mac: parser.error("-m or --mac option is required.") if not validateMac(options.mac): parser.error("Invalid format for mac address. Format: xx:xx:xx:xx:xx:xx") controller = options.controller host = options.mac url = 'http://%s:8080/wm/core/packettrace/json' % controller filter = {'mac':host, 'direction':'both', 'period':1000} post_data = json.dumps(filter) request = urllib2.Request(url, post_data, {'Content-Type':'application/json'}) response_text = None def terminateTrace(sid): global controller filter = {SESSIONID:sid, 'period':-1} post_data = json.dumps(filter) url = 'http://%s:8080/wm/core/packettrace/json' % controller request = urllib2.Request(url, post_data, {'Content-Type':'application/json'}) try: response = urllib2.urlopen(request) response_text = response.read() except Exception, e: # Floodlight may not be running, but we don't want that to be a fatal # error, so we just ignore the exception in that case. print "Exception:", e try: response = urllib2.urlopen(request) response_text = response.read() except Exception, e: # Floodlight may not be running, but we don't want that to be a fatal # error, so we just ignore the exception in that case. print "Exception:", e exit if not response_text: print "Failed to start a packet trace session" sys.exit() response_text = json.loads(response_text) sessionId = None if SESSIONID in response_text: sessionId = response_text[SESSIONID] else: print "Failed to start a packet trace session" sys.exit() try: # Make socket transport = TSocket.TSocket('localhost', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TFramedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = PacketStreamer.Client(protocol) # Connect! transport.open() while 1: packets = client.getPackets(sessionId) for packet in packets: print "Packet: %s"% packet if "FilterTimeout" in packet: sys.exit() except Thrift.TException, e: print '%s' % (e.message) terminateTrace(sessionId) except KeyboardInterrupt, e: terminateTrace(sessionId) # Close! transport.close() floodlight-0.90/example/cli.py0000775000175000017500000000646012041336206017033 0ustar jamespagejamespage#!/usr/bin/python import sys import argparse import json import httplib import urllib2 class RestApi(object): def __init__(self, server,port): self.server = server self.port = port def get(self, path): #ret = self.rest_call(path, {}, 'GET') #return ret[2] f = urllib2.urlopen('http://'+self.server+':'+str(self.port)+path) ret = f.read() return json.loads(ret) def set(self, path, data): ret = self.rest_call(path, data, 'POST') return ret[0] == 200 def remove(self, objtype, data): #ret = self.rest_call(data, 'DELETE') return ret[0] == 200 def rest_call(self, path, data, action): headers = { 'Content-type': 'application/json', 'Accept': 'application/json', } body = json.dumps(data) conn = httplib.HTTPConnection(self.server, self.port) conn.request(action, path, body, headers) response = conn.getresponse() ret = (response.status, response.reason, response.read()) conn.close() print str(ret[2]) return ret usage_desc = """ Command descriptions: host [debug] link [tunnellinks] port memory switch switchclusters counter [DPID] switch_stats [DPID] """ def lookupPath(cmd): path = '' numargs = len(args.otherargs) if args.cmd == 'switch_stats': if numargs == 1: path = '/wm/core/switch/all/'+args.otherargs[0]+'/json' elif numargs == 2: path = '/wm/core/switch/'+args.otherargs[0]+'/'+args.otherargs[1]+'/json' elif args.cmd == 'switch': path = '/wm/core/controller/switches/json' elif args.cmd == 'counter': if numargs == 1: path = '/wm/core/counter/'+args.otherargs[0]+'/json' elif numargs == 2: path = '/wm/core/counter/'+args.otherargs[0]+'/'+args.otherargs[1]+'/json' elif args.cmd == 'memory': path = '/wm/core/memory/json' elif args.cmd == 'link': if numargs == 0: path = '/wm/topology/links/json' elif numargs == 1: path = '/wm/topology/'+args.otherargs[0]+'/json' elif args.cmd == 'port' and numargs == 1: if args.otherargs[0] == "blocked": path = '/wm/topology/blockedports/json' elif args.otherargs[0] == "broadcast": path = '/wm/topology/broadcastdomainports/json' elif args.cmd == 'switchclusters': path = '/wm/topology/switchclusters/json' elif args.cmd == 'host': path = '/wm/device/' if len(args.otherargs) == 1 and args.otherargs[0] == 'debug': path = '/wm/device/debug' else: print usage_desc path = '' exit(0) return path parser = argparse.ArgumentParser(description='process args', usage=usage_desc, epilog='foo bar help') parser.add_argument('--ip', default='localhost') parser.add_argument('--port', default=8080) parser.add_argument('cmd') parser.add_argument('otherargs', nargs='*') args = parser.parse_args() #print args rest = RestApi(args.ip, args.port) path = lookupPath(args.cmd) out = rest.get(path) print json.dumps(out,sort_keys=True, indent=4) print "Number of items: " + str(len(out)) floodlight-0.90/example/graphTopo.py0000775000175000017500000000405712041336206020227 0ustar jamespagejamespage#!/usr/bin/python import urllib2 import json import sys def simple_json_get(url): return json.loads(urllib2.urlopen(url).read()) def shorten(s): return s.replace('net.floodlightcontroller','n.f' ).replace('com.bigswitch','c.b') def usage(s): sys.stderr.write("Usage:\ngrahTopo.py hostname [port]\n%s" % s) sys.stderr.write("\n\n\n\n writes data to 'hostname.dot' for use with graphviz\n") sys.exit(1) if __name__ == '__main__': host='localhost' port=8080 if len(sys.argv) == 1 or sys.argv[1] == '-h' or sys.argv[1] == '--help': usage("need to specify hostname") host = sys.argv[1] if len(sys.argv) > 2: port = int(sys.argv[2]) sys.stderr.write("Connecting to %s:%d ..." % (host,port)) URL="http://%s:%d/wm/topology/links/json" % (host,port) # { # "dst-port": 2, # "dst-switch": "00:00:00:00:00:00:00:0a", # "src-port": 3, # "src-switch": "00:00:00:00:00:00:00:0c" # } links = simple_json_get(URL) nodeMap = {} sys.stderr.write("Writing to %s.dot ..." % (host)) f = open("%s.dot" % host, 'w') f.write( "digraph Deps {\n") for link in links: # sys.stderr.write("Discovered module %s\n" % mod) if not link['dst-switch'] in nodeMap: sw = link['dst-switch'] nodeMap[sw] = "n%d" % len(nodeMap) f.write(" %s [ label=\"dpid=%s\", color=\"blue\"];\n" % (nodeMap[sw], sw)) if not link['src-switch'] in nodeMap: sw = link['src-switch'] nodeMap[sw] = "n%d" % len(nodeMap) f.write(" %s [ label=\"dpid=%s\", color=\"blue\"];\n" % (nodeMap[sw], sw)) f.write(" %s -> %s [ label=\"%s\"];\n" % ( nodeMap[link['dst-switch']], nodeMap[link['src-switch']], "src_port %d --> dst_port %d" % (link['src-port'],link['dst-port']) ) ) f.write("}\n") f.close(); sys.stderr.write("Now type\ndot -Tpdf -o %s.pdf %s.dot\n" % ( host, host)) floodlight-0.90/example/graphDeps.py0000775000175000017500000000404112041336206020172 0ustar jamespagejamespage#!/usr/bin/python import urllib2 import json import sys def simple_json_get(url): return json.loads(urllib2.urlopen(url).read()) def shorten(s): return s.replace('net.floodlightcontroller','n.f' ).replace('com.bigswitch','c.b') def usage(s): sys.stderr.write("Usage:\ngrahDeps.py hostname [port]\n%s" % s) sys.stderr.write("\n\n\n\n writes data to 'hostname.dot' for use with graphviz\n") sys.exit(1) if __name__ == '__main__': host='localhost' port=8080 if len(sys.argv) == 1 or sys.argv[1] == '-h' or sys.argv[1] == '--help': usage("need to specify hostname") host = sys.argv[1] if len(sys.argv) > 2: port = int(sys.argv[2]) sys.stderr.write("Connecting to %s:%d ..." % (host,port)) URL="http://%s:%d/wm/core/module/loaded/json" % (host,port) deps = simple_json_get(URL) serviceMap = {} nodeMap = {} nodeCount = 0 sys.stderr.write("Writing to %s.dot ..." % (host)) f = open("%s.dot" % host, 'w') f.write( "digraph Deps {\n") for mod, info in deps.iteritems(): # sys.stderr.write("Discovered module %s\n" % mod) nodeMap[mod] = "n%d" % nodeCount nodeCount += 1 label = shorten(mod) + "\\n" for service, serviceImpl in info['provides'].iteritems(): # sys.stderr.write(" Discovered service %s implemented with %s\n" % (service,serviceImpl)) label += "\\nService=%s" % shorten(service) serviceMap[serviceImpl] = mod f.write(" %s [ label=\"%s\", color=\"blue\"];\n" % (nodeMap[mod], label)) f.write("\n") # for readability for mod, info in deps.iteritems(): for dep, serviceImpl in info['depends'].iteritems(): f.write(" %s -> %s [ label=\"%s\"];\n" % ( nodeMap[mod], shorten(nodeMap[serviceMap[serviceImpl]]), shorten(dep))) f.write("}\n") f.close(); sys.stderr.write("Now type\ndot -Tpdf -o %s.pdf %s.dot\n" % ( host, host)) floodlight-0.90/example/README0000664000175000017500000000163612041336206016567 0ustar jamespagejamespageOne of Floodlight's main goals is extensibility and flexibility. To prove that point, this directory includes a number of useful utilities as examples of what can do with this extensibility. UTILITIES: -------------------------- graphDeps.py and graphTopo.py Read the module dependencies (graphDeps.py) or the topology from the REST API and output it in the 'dot' format used by the popular graphviz (www.graphviz.org) package so that they can be visualized. Example usage: ./graphTopo.py $hostname # generate .dot file dot -Tpdf -o $hostname.pdf $hostname.dot # convert to PDF open $hostname.pdf # open to view topology packetStreamerClientExample.py Example client for the packet streamer server in floodlight. Allows you to intercept packets from floodlight's packet_in processing chain and read them. floodlight-0.90/setup-eclipse.sh0000775000175000017500000000232212041336206017366 0ustar jamespagejamespage#!/bin/bash d=$(dirname $0) MAIN_CLASS=$1 LIBRARIES=$2 [ "${MAIN_CLASS}" ] || { echo "Run 'ant eclipse' to generate Eclipse project files"; exit 1; } cat >$d/.project < floodlight org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature EOF cat >$d/.classpath < EOF ( IFS=":" for l in ${LIBRARIES}; do cat >>$d/.classpath < EOF done ) cat >>$d/.classpath < EOF