123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380openCoreopenAsyncopenFrenetic_netkat.SyntaxmoduleNetkat=Frenetic_netkatmoduleController=NetKAT_Controller.Make(OpenFlow0x01_Plugin)moduleField=Netkat.Fdd.Fieldtypeshowable=(* usage: order
* Shows the ordering that will be used on the next update. *)|Ordering(* usage: policy
* Shows the policy that is currently active. *)|Policy(* usage: flow-table [policy]
* Shows the flow-table produced by current policy *)|FlowTable(* usage: help
* Displays a helpful message. *)|Helptypecommand=(* usage: update <policy>
* Compiles the specified local policy using the current ordering
* and updates the controller with the new flow-table *)|Updateof(policy*string)(* usage: update-global <policy>
* Compiles the specified global policy using the current ordering
* and updates the controller with the new flow-table *)|UpdateGlobalof(policy*string)(* usage: order <ordering>
* Sets the order which the compiler will select field names when
* constructing the BDD.
* Valid orderings:
* heuristic - Uses a heuristic to select the order of fields
* default - Uses the default ordering as specified in Frenetic_netkat.LocalCompiler
* f_1 < f_2 [ < f_3 < ... < f_n ] - Given two or more fields, ensures the
* order of the specified fields is maintained. *)|OrderofNetkat.Local_compiler.order(* usage: remove_tail_drops
* Remove any drop rules at the end of each flow table. Toggles setting.
*)|ToggleRemoveTailDrops(* usage: exit
* Exits the shell. *)|Exit(* usage: quit
* Exits the shell. *)|Quit(* usage: load <filename>
* Loads the specified file as a local policy and compiles it updating
the controller with the new flow table. *)|Loadofstring(* usage: load-global <filename>
* Like load, but for global policy *)|LoadGlobalofstring(* See showables for more details *)|ShowofshowablemoduleParser=structopenMParsermoduleTokens=MParser_RE.Tokens(* Parser for field as the to_string function displays it *or*
* all lowercase for convenience. *)letfield(f:Field.t):(Field.t,byteslist)MParser.t=Tokens.symbol(Field.to_stringf|>String.lowercase)<|>Tokens.symbol(Field.to_stringf)>>returnf(* Parser for any of the fields *)letany_field:(Field.t,byteslist)MParser.t=fieldField.Switch<|>fieldField.Location<|>fieldField.EthSrc<|>fieldField.EthDst<|>fieldField.Vlan<|>fieldField.VlanPcp<|>fieldField.EthType<|>fieldField.IPProto<|>fieldField.IP4Src<|>fieldField.IP4Dst<|>fieldField.TCPSrcPort<|>fieldField.TCPDstPort(* Parser that produces the Order command or Show Order command *)letorder:(command,byteslist)MParser.t=Tokens.symbol"order">>((eof>>return(ShowOrdering))<|>(Tokens.symbol"heuristic">>return(Order`Heuristic))<|>(Tokens.symbol"default">>return(Order`Default))<|>(sep_by1any_field(Tokens.symbol"<")>>=funfields->eof>>return(Order(`Staticfields))))(* Mostly useless error message for parsing policies *)letstring_of_position(p:Lexing.position):string=sprintf"%s:%d:%d"p.pos_fnamep.pos_lnum(p.pos_cnum-p.pos_bol)(* Use the netkat parser to parse policies *)letparse_policy?(name="")(pol_str:string):(policy,string)Result.t=Ok(Frenetic_netkat.Parser.pol_of_stringpol_str)(* Parser for netkat policies *)letpolicy':((policy*string),byteslist)MParser.t=many_untilany_chareof>>=funpol_chars->letpol_str=String.of_char_listpol_charsinmatchparse_policypol_strwith|Okpol->return(pol,pol_str)|Errormsg->failmsg(* Parser for the Update command *)letupdate:(command,byteslist)MParser.t=Tokens.symbol"update">>policy'>>=(funpol->return(Updatepol))(* Parser for the Update global command *)letupdate_global:(command,byteslist)MParser.t=Tokens.symbol"update-global">>policy'>>=(funpol->return(UpdateGlobalpol))(* Parser for the help command *)lethelp:(command,byteslist)MParser.t=Tokens.symbol"help">>return(ShowHelp)(* Parser for the exit command *)letexit:(command,byteslist)MParser.t=Tokens.symbol"exit">>returnExit(* Parser for the exit command *)letquit:(command,byteslist)MParser.t=Tokens.symbol"quit">>returnQuit(* Parser for the load command *)letload:(command,byteslist)MParser.t=Tokens.symbol"load">>many_untilany_chareof>>=(funfilename->return(Load(String.of_char_listfilename)))(* Parser for the load-global command *)letload_global:(command,byteslist)MParser.t=Tokens.symbol"load-global">>many_untilany_chareof>>=(funfilename->return(LoadGlobal(String.of_char_listfilename)))(* Parser for the policy command *)letpolicy:(command,byteslist)MParser.t=Tokens.symbol"policy">>return(ShowPolicy)(* Parser for the remove_tail_drops command *)letremove_tail_drops:(command,byteslist)MParser.t=Tokens.symbol"remove_tail_drops">>returnToggleRemoveTailDrops(* Parser for the flow-table command *)letflowtable:(command,byteslist)MParser.t=Tokens.symbol"flow-table">>eof>>return(ShowFlowTable)(* Parser for commands *)letcommand:(command,byteslist)MParser.t=order<|>update_global<|>update<|>policy<|>help<|>flowtable<|>remove_tail_drops<|>load_global<|>load<|>exit<|>quitend(* TODO(jcollard): The cache flag here is actually a problem. Changing ordering won't work as expected. *)letcurrent_compiler_options=ref{Netkat.Local_compiler.default_compiler_optionswithcache_prepare=`Keep}letset_field_orderord:unit=current_compiler_options:={!current_compiler_optionswithfield_order=ord}(* Prints the current ordering mode. *)letprint_order():unit=(!current_compiler_options).field_order|>Netkat.Local_compiler.field_order_to_string|>printf"Ordering Mode: %s\n%!"(* Convenience function that checks that an ordering doesn't contain
* duplicates. This is used in favor of List.contains_dup so a better
* error message can be produced *)letreccheck_duplicates(fs:Field.tlist)(acc:Field.tlist):bool=matchfswith|[]->false|(f::rest)->ifList.memaccf~equal:Field.equalthen(printf"Invalid ordering: %s < %s"(Field.to_stringf)(Field.to_stringf);false)elsecheck_duplicatesrest(f::acc)(* Given an ordering, sets the order reference.
* If a Static ordering is given with duplicates, the ordering
* is not updated and an error message is printed *)letset_order(o:Netkat.Local_compiler.order):unit=matchowith|`Heuristic->set_field_order`Heuristic;print_order()|`Default->set_field_order`Default;print_order()|`Staticls->ifcheck_duplicatesls[]then()elseletcurr_order=match(!current_compiler_options).field_orderwith|`Heuristic->Field.all|`Default->Field.all|`Staticfields->fieldsinletremoved=List.filtercurr_order(Fn.composenot(List.memls~equal:Field.equal))in(* Tags all specified Fields at the highest priority *)letnew_order=List.append(List.revls)removedinset_field_order(`Staticnew_order);print_order()lettoggle_remove_tail_drops()=letcurrent_setting=(!current_compiler_options).remove_tail_dropsincurrent_compiler_options:={!current_compiler_optionswithremove_tail_drops=notcurrent_setting};printf"Remove Tail Drops: %B\n%!"(!current_compiler_options).remove_tail_drops(* A reference to the current policy and the associated string. *)letpolicy:[`Localof(policy*string)|`Globalof(policy*string)]ref=ref(`Local(drop,"drop"))letcompile_current()=match!policywith|`Local(p,_)->Netkat.Local_compiler.compile~options:(!current_compiler_options)p|`Global(p,_)->Netkat.Global_compiler.compile~options:(!current_compiler_options)p(* Prints the current policy *)letprint_policy()=match!policywith|`Local(_,p)->printf"Local policy:\n%s\n%!"p|`Global(_,p)->printf"Global policy:\n%s\n%!"p(* Print the flowtables associated with the current policy *)letprint_policy_table():unit=letpol=match!policywith`Local(p,_)|`Global(p,_)->pinletfdd=compile_current()inletswitches=Frenetic_netkat.Semantics.switches_of_policypolin(ifList.is_emptyswitchesthen[0L]elseswitches)|>List.map~f:(funsw->Netkat.Local_compiler.to_table~options:(!current_compiler_options)swfdd|>Frenetic_kernel.OpenFlow.string_of_flowTable~label:(Int64.to_stringsw))|>String.concat~sep:"\n\n"|>printf"%s%!"letparse_command(line:string):commandoption=match(MParser.parse_stringParser.commandline[])with|Successcommand->Somecommand|Failed(msg,e)->(print_endlinemsg;None)lethelp=String.concat~sep:"\n"["";"commands:";" order - Display the ordering that will be used when compiling.";" order <ordering> - Changes the order in which the compiler selects fields.";"";" orderings: heuristic";" default";" f_1 < f_2 [ < f_3 < ... < f_n ]";"";" fields: Switch, Location, EthSrc, EthDst, Vlan, VlanPcP,";" EthType, IPProto, IP4Src, IP4Dst, TCPSrcPort,";" TCPDstPort";"";" policy - Displays the policy that is currently active.";"";" flow-table - Displays the flow-table produced by the specified policy.";" If no policy is specified, the current policy is used.";"";" update <policy> - Compiles the specified local policy using the current";" ordering and updates the controller with the resulting";" flow-table.";"";" update-global <pol> - Like update, but with a global policy.";"";" load <file> - Loads local policy from the specified file, compiles it,";" and updates the controller with the resulting flow-table.";"";" load-global <file> - Like load, but with global policy.";"";" remove_tail_drops - Remove drop rules at the end of each flow-table. Toggles ";" setting.";"";" help - Displays this message.";"";" exit - Exits Frenetic Shell.";"";" quit - Exits Frenetic Shell. Equivalent to CTRL-D";""]letprint_help():unit=printf"%s\n%!"help(* Loads a policy from a file and updates the controller *)letload_file(typ:[`Local|`Global])(filename:string):unit=tryletopenIn_channelinletchan=createfilenameinletpolicy_string=input_allchaninletpol=Parser.parse_policypolicy_stringinclosechan;matchpolwith|Okp->policy:=beginmatchtypwith|`Local->`Local(p,policy_string)|`Global->`Global(p,policy_string)end;print_policy();compile_current()|>Controller.update_fdd|>don't_wait_for|Errormsg->print_endlinemsgwith|Sys_errormsg->printf"Load failed: %s\n%!"msgletrecrepl():unitDeferred.t=printf"frenetic> %!";Reader.read_line(Lazy.forceReader.stdin)>>=funinput->lethandleline=trymatchlinewith|`Eof->Shutdown.shutdown0|`Okline->matchparse_commandlinewith|SomeExit|SomeQuit->print_endline"Goodbye!";Shutdown.shutdown0|Some(ShowOrdering)->print_order()|Some(ShowPolicy)->print_policy()|Some(ShowHelp)->print_help()|Some(ShowFlowTable)->print_policy_table()|Some(Update(pol,pol_str))->policy:=`Local(pol,pol_str);compile_current()|>Controller.update_fdd|>don't_wait_for|Some(UpdateGlobal(pol,pol_str))->policy:=`Global(pol,pol_str);compile_current()|>Controller.update_fdd|>don't_wait_for|Some(Loadfilename)->load_file`Localfilename|Some(LoadGlobalfilename)->load_file`Globalfilename|Some(Orderorder)->set_orderorder|Some(ToggleRemoveTailDrops)->toggle_remove_tail_drops()|None->()withexn->Location.report_exceptionFormat.std_formatterexninhandleinput;repl()letlog_file="frenetic.log"letmain(openflow_port:int)():unit=Logging.set_output[Async.Log.Output.file`Textlog_file];printf"Frenetic Shell v 4.0\n%!";printf"Type `help` for a list of commands\n%!";Controller.startopenflow_port;let_=repl()in()