package p4spectec
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
P4-SpecTec: A mechanization toolchain for the P4 Programming Language
Install
dune-project
Dependency
Authors
Maintainers
Sources
v0.1.2.tar.gz
md5=1a3bc0a385fe1ecf403c019f49aa6de6
sha512=5d20b5821f33e2a3a5419b208606f27c01511994c2b3b1e1cdf4c077056dfd0aa81682af0720e1060ee2bfb0341918fcc4c53159820205a2bc32b725e5c1a714
doc/src/p4spectec.backend_sim/make.ml.html
Source file make.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423module Typ = Runtime.Type.Typ module Value = Runtime.Value open Runtime.Sim.Io open Runtime.Sim.Signature open Error open Util.Source (* Functor to create a SIM from ARCH and INTERP implementations *) module Make (Interface : INTERFACE) (MakeArch : functor (Spec : Spec.S) -> ARCH) (MakeInterp_AL : functor (Interface : INTERFACE) (Extern : EXTERN) () -> INTERP_AL) (MakeInterp_SL : functor (Interface : INTERFACE) (Extern : EXTERN) () -> INTERP_SL) (MakeInterp_PL : functor (Interface : INTERFACE) (Extern : EXTERN) () -> INTERP_PL) : SIM = struct (* Instantiations *) (* Spec_ is a trampoline to allow Arch/Table to call back into the Interp modules *) module Spec_ = Spec.Make () module Arch = MakeArch (Spec_) module Table = Table.Make (Spec_.Func) module MakeExtern (Interp_AL : INTERP_AL) (Interp_SL : INTERP_SL) (Interp_PL : INTERP_PL) : EXTERN = struct let init_mode mode_ = let call_func name typs values = (match mode_ with | AL_mode -> Interp_AL.eval_func name typs values | SL_mode -> Interp_SL.eval_func name typs values | PL_mode -> Interp_PL.eval_func name typs values | Empty_mode -> assert false) |> function | Pass value -> value | Fail (at, msg) -> error at msg in let call_rel name values = (match mode_ with | AL_mode -> Interp_AL.eval_rel name values | SL_mode -> Interp_SL.eval_rel name values | PL_mode -> Interp_PL.eval_rel name values | Empty_mode -> assert false) |> function | Pass values -> values | Fail (at, msg) -> error at msg in let call_pgm relname includes path = (match mode_ with | AL_mode -> Interp_AL.eval_program relname includes path | SL_mode -> Interp_SL.eval_program relname includes path | PL_mode -> Interp_PL.eval_program relname includes path | Empty_mode -> assert false) |> function | Pass [ value_ctx; value_arch ] -> (value_ctx, value_arch) | Pass _ -> error no_region "unexpected number of return values" | Fail (`Syntax (at, msg) | `Runtime (at, msg)) -> error at msg in Spec_.Func.register call_func; Spec_.Rel.register call_rel; Spec_.Pgm.register call_pgm let checkpoint () : int = 0 let seff (before : int) (after : int) : bool = before <> after let clear () = () module Cache = struct let cache_on () = () let cache_off () = () end let eval_extern_rel = Arch.eval_extern_rel let eval_extern_func = Arch.eval_extern_func end include ( Runner.Make.Make_rec (Interface) (MakeExtern) (MakeInterp_AL) (MakeInterp_SL) (MakeInterp_PL) : RUNNER) (* Logger *) let verbose = ref true let log (msg : string) : unit = if !verbose then print_endline msg (* STF test runner *) (* Find the first expect element that has the same output port, then compare packet output. Return matched element and the rest of the list, preserving order. *) let extract_matching_expect (tx : IO.tx) (expect_queue : IO.expect list) : (IO.expect * IO.expect list) option = let tx_port, _ = tx in let rec extract_matching_expect expects = function | [] -> None | expect_h :: expect_t -> let (expect_port, expect_packet), exact = expect_h in if expect_port = tx_port then if compare_tx ~exact tx (expect_port, expect_packet) then Some (expect_h, List.rev_append expects expect_t) else error_stf (Format.asprintf "expected %s but got %s" (string_of_tx (expect_port, expect_packet)) (string_of_tx tx)) else extract_matching_expect (expect_h :: expects) expect_t in extract_matching_expect [] expect_queue let on_tx_output (txs : IO.tx list) (tx_output_queue : IO.tx list) (expect_queue : IO.expect list) : IO.tx list * IO.expect list = match txs with (* Packet was dropped *) | [] -> (tx_output_queue, expect_queue) (* Packet was transmitted *) | tx_h :: tx_t -> ( match extract_matching_expect tx_h expect_queue with | None -> (* No expected packet (yet) *) let tx_output_queue = tx_output_queue @ txs in (tx_output_queue, expect_queue) | Some (expect, expect_queue) -> let tx, _ = expect in Format.asprintf "[PASS] Transmitted %s" (string_of_tx tx) |> log; (tx_output_queue @ tx_t, expect_queue)) let extract_matching_output (expect : IO.expect) (tx_output_queue : IO.tx list) : (IO.tx * IO.tx list) option = let (expect_port, expect_packet), exact = expect in let rec extract_matching_output txs = function | [] -> None | tx_h :: tx_t -> let tx_port, _ = tx_h in if expect_port = tx_port then if compare_tx ~exact tx_h (expect_port, expect_packet) then Some (tx_h, List.rev_append txs tx_t) else error_stf (Format.asprintf "expected %s but got %s" (string_of_tx (expect_port, expect_packet)) (string_of_tx tx_h)) else extract_matching_output (tx_h :: txs) tx_t in extract_matching_output [] tx_output_queue let on_tx_expect (expect : IO.expect) (tx_output_queue : IO.tx list) (expect_queue : IO.expect list) : IO.tx list * expect list = match extract_matching_output expect tx_output_queue with | None -> (* No output packet (yet) *) let expect_queue = expect_queue @ [ expect ] in (tx_output_queue, expect_queue) | Some (tx_output, tx_output_queue) -> Format.asprintf "[PASS] Transmitted %s" (string_of_tx tx_output) |> log; (tx_output_queue, expect_queue) let run_stf_stmt (value_ctx : Value.t) (value_arch : Value.t) (tx_output_queue : IO.tx list) (expect_queue : IO.expect list) (stmt_stf : Stf.Ast.stmt) : Value.t * Value.t * IO.tx list * IO.expect list = (* Apply architecture-specific STF transformation *) let stmt_stf = Arch.transform_stf_stmt stmt_stf in match stmt_stf with (* Packet I/O *) | Stf.Ast.Packet (port_in, packet_in) -> let port_in = int_of_string port_in in let packet_in = String.uppercase_ascii packet_in in let rx = (port_in, packet_in) in let value_ctx, value_arch, tx_outputs = Arch.drive_pipe value_ctx value_arch rx in let tx_output_queue, expect_queue = on_tx_output tx_outputs tx_output_queue expect_queue in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.Expect (port_expect, packet_expect_opt, exact) -> let port_expect = int_of_string port_expect in let packet_expect = Option.value packet_expect_opt ~default:"" in let packet_expect = String.uppercase_ascii packet_expect in let expect = ((port_expect, packet_expect), exact) in let tx_output_queue, expect_queue = on_tx_expect expect tx_output_queue expect_queue in (value_ctx, value_arch, tx_output_queue, expect_queue) (* Match-action table updates *) | Stf.Ast.Add ( table_name, table_entry_priority_opt, table_entry_keys, table_entry_action, _ ) -> (* Encode name *) let value_tableName = table_name |> String.escaped |> Value.Make.text in (* Encode priority *) let value_tableEntryPriorityInterface = table_entry_priority_opt |> Option.map (fun table_entry_priority -> table_entry_priority |> Bigint.of_int |> Value.Make.int) |> Value.Make.opt (Typ.Make.opt Typ.Make.int) in (* Encode keys *) let typ_tableKeyInterface = Typ.Make.var ("tableKeyInterface" $ no_region) [] in let typ_tableKeysetInterface = Typ.Make.list typ_tableKeyInterface in let value_tableKeysetInterface = table_entry_keys |> List.map (fun (table_entry_key : Stf.Ast.mtch) -> let table_key_name, table_key_value = table_entry_key in let table_key_name = Stf.Print.convert_dollar_to_brackets table_key_name in let value_table_key_name = Value.Make.text table_key_name in let value_table_key_value = match table_key_value with | Num number -> if String.starts_with ~prefix:"0x" number then let number_base_len = String.length number - 2 in let number_base = String.sub number 2 number_base_len in Value.Make.( "_HEX text" <| [ text number_base ] <<| "tableKeyValueInterface") else if String.starts_with ~prefix:"0b" number then let number_base_len = String.length number - 2 in let number_base = String.sub number 2 number_base_len in Value.Make.( "_BIN text" <| [ text number_base ] <<| "tableKeyValueInterface") else Value.Make.( "_DEC text" <| [ text number ] <<| "tableKeyValueInterface") | Slash (prefix, mask) -> let value_prefix = Value.Make.text prefix in let mask = Bigint.of_int (int_of_string mask) in let value_mask = Value.Make.nat mask in Value.Make.( "text _SLASH nat" <| [ value_prefix; value_mask ] <<| "tableKeyValueInterface") in Value.Make.tuple typ_tableKeyInterface [ value_table_key_name; value_table_key_value ]) |> Value.Make.list typ_tableKeysetInterface in (* Encode action *) let value_tableActionInterface = let table_action_name, table_action_args = table_entry_action in let typ_tableActionInterface = Typ.Make.var ("tableActionInterface" $ no_region) [] in let typ_tableActionArgumentInterface = Typ.Make.var ("tableActionArgumentInterface" $ no_region) [] in let typ_tableActionArgumentInterfaceList = Typ.Make.list typ_tableActionArgumentInterface in let value_table_action_name = Value.Make.text table_action_name in let value_tableActionArgumentInterfaces = table_action_args |> List.map (fun (name, number) -> let value_name = Value.Make.text name in let value_number = number |> int_of_string |> Bigint.of_int |> Value.Make.int in Value.Make.tuple typ_tableActionArgumentInterface [ value_name; value_number ]) |> Value.Make.list typ_tableActionArgumentInterfaceList in Value.Make.tuple typ_tableActionInterface [ value_table_action_name; value_tableActionArgumentInterfaces ] in let value_arch = Table.add_entry value_ctx value_arch value_tableName value_tableEntryPriorityInterface value_tableKeysetInterface value_tableActionInterface in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.SetDefault (table_name, table_entry_action) -> (* Encode name *) let value_tableName = Value.Make.text table_name in (* Encode action *) let value_tableActionInterface = let table_action_name, table_action_args = table_entry_action in let typ_tableActionInterface = Typ.Make.var ("tableActionInterface" $ no_region) [] in let typ_tableActionArgumentInterface = Typ.Make.var ("tableActionArgumentInterface" $ no_region) [] in let typ_tableActionArgumentInterfaceList = Typ.Make.list typ_tableActionArgumentInterface in let value_table_action_name = Value.Make.text table_action_name in let value_tableActionArgumentInterfaces = table_action_args |> List.map (fun (name, number) -> let value_name = Value.Make.text name in let value_number = number |> int_of_string |> Bigint.of_int |> Value.Make.int in Value.Make.tuple typ_tableActionArgumentInterface [ value_name; value_number ]) |> Value.Make.list typ_tableActionArgumentInterfaceList in Value.Make.tuple typ_tableActionInterface [ value_table_action_name; value_tableActionArgumentInterfaces ] in let value_arch = Table.add_default_action value_ctx value_arch value_tableName value_tableActionInterface in (value_ctx, value_arch, tx_output_queue, expect_queue) (* Mirror session updates *) | Stf.Ast.MirroringAdd (session, port) -> let session = int_of_string session in let port = int_of_string port in let value_arch = Arch.add_mirror_session value_arch session port in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.MirroringAddMc (session, id) -> let session = int_of_string session in let id = int_of_string id in let value_arch = Arch.add_mirror_session_mc value_arch session id in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.MirroringGet _session -> (value_ctx, value_arch, tx_output_queue, expect_queue) (* Multicast group updates *) | Stf.Ast.McGroupCreate mgid -> let mgid = int_of_string mgid in let value_arch = Arch.mc_mgrp_create value_arch mgid in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.McNodeCreate (rid, ports) -> let rid = int_of_string rid in let ports = List.map int_of_string ports in let value_arch = Arch.mc_node_create value_arch rid ports in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.McNodeAssociate (mgid, handle) -> let mgid = int_of_string mgid in let handle = int_of_string handle in let value_arch = Arch.mc_node_associate value_arch mgid handle in (value_ctx, value_arch, tx_output_queue, expect_queue) (* Register updates *) | Stf.Ast.RegisterRead (reg_name, index) -> let index = int_of_string index in let value_arch = Arch.register_read value_arch reg_name index in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.RegisterWrite (reg_name, index, value) -> let index = int_of_string index in let value = int_of_string value in let value_arch = Arch.register_write value_arch reg_name index value in (value_ctx, value_arch, tx_output_queue, expect_queue) | Stf.Ast.RegisterReset reg_name -> let value_arch = Arch.register_reset value_arch reg_name in (value_ctx, value_arch, tx_output_queue, expect_queue) (* Async *) | Stf.Ast.Wait -> (value_ctx, value_arch, tx_output_queue, expect_queue) | _ -> error_stf (Format.asprintf "not yet supported: %a" Stf.Print.print_stmt stmt_stf) let run_stf_stmts (value_ctx : Value.t) (value_arch : Value.t) (stmts_stf : Stf.Ast.stmt list) : unit = let _, _, tx_output_queue, expect_queue = List.fold_left (fun (value_ctx, value_arch, tx_output_queue, expect_queue) stmt_stf -> run_stf_stmt value_ctx value_arch tx_output_queue expect_queue stmt_stf) (value_ctx, value_arch, [], []) stmts_stf in match (tx_output_queue, expect_queue) with | [], [] -> () | tx_output_queue, expect_queue -> let msg_output = if tx_output_queue <> [] then Format.asprintf "[FAIL] Remaining packets to be matched:\n%s" (tx_output_queue |> List.map string_of_tx |> String.concat "\n") else "" in let msg_expect = if expect_queue <> [] then Format.asprintf "[FAIL] Expected packets to be output:\n%s" (expect_queue |> List.map (fun (tx, _) -> string_of_tx tx) |> String.concat "\n") else "" in error_stf (msg_output ^ msg_expect) let run_stf_test (includes_p4 : string list) (path_p4 : string) (path_stf : string) : stf_result = try let value_ctx, value_arch = Arch.init_pipe includes_p4 path_p4 in let stf_stmts = Stf.Parse.parse_file path_stf in run_stf_stmts value_ctx value_arch stf_stmts; Pass with | Util.Error.ParseError (at, msg) -> Fail (`Syntax (at, msg)) | Util.Error.InterpError (at, msg) | Util.Error.ExternError (at, msg) -> Fail (`Runtime (at, msg)) | Util.Error.StfError msg -> Fail (`Runtime (no_region, msg)) end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>