From 4aee642874a29f4f77704c97286f201d3c4bd2c3 Mon Sep 17 00:00:00 2001 From: John Estabrook <jestabro@vyos.io> Date: Wed, 23 Oct 2024 18:50:46 -0500 Subject: T6718: move vyos1x-adapter into subdirectory The vyos1x-adapter provides access to the legacy CStore set/delete functions using ctypes. Developed as a separate package, include as a subdir, to be retired when full replacements are available. --- src/adapter/vy_delete.ml | 40 ++++++++++++ src/adapter/vy_load_config.ml | 47 ++++++++++++++ src/adapter/vy_set.ml | 79 +++++++++++++++++++++++ src/adapter/vyos1x_adapter.ml | 140 +++++++++++++++++++++++++++++++++++++++++ src/adapter/vyos1x_adapter.mli | 16 +++++ 5 files changed, 322 insertions(+) create mode 100644 src/adapter/vy_delete.ml create mode 100644 src/adapter/vy_load_config.ml create mode 100644 src/adapter/vy_set.ml create mode 100644 src/adapter/vyos1x_adapter.ml create mode 100644 src/adapter/vyos1x_adapter.mli (limited to 'src/adapter') diff --git a/src/adapter/vy_delete.ml b/src/adapter/vy_delete.ml new file mode 100644 index 0000000..652fdad --- /dev/null +++ b/src/adapter/vy_delete.ml @@ -0,0 +1,40 @@ +let path_opt = ref [] + +let usage = "Usage: " ^ Sys.argv.(0) ^ " [options]" + +let read_path p = + path_opt := p::!path_opt + +let speclist = [ + ] + +let () = + let () = Arg.parse speclist read_path usage in + let path_list = List.rev !path_opt in + let () = + if List.length path_list = 0 then + (Printf.printf "no path specified\n"; exit 1) + in + let handle = + let h = Vyos1x_adapter.cstore_handle_init () in + if not (Vyos1x_adapter.cstore_in_config_session_handle h) then + (Vyos1x_adapter.cstore_handle_free h; + Printf.printf "not in config session\n"; exit 1) + else Some h + in + let output = + match handle with + | Some h -> Vyos1x_adapter.cstore_delete_path h path_list + | None -> "missing session handle" + in + let ret = + if output = "" then 0 + else 1 + in + let () = + match handle with + | Some h -> Vyos1x_adapter.cstore_handle_free h + | None -> () + in + let () = print_endline output in + exit ret diff --git a/src/adapter/vy_load_config.ml b/src/adapter/vy_load_config.ml new file mode 100644 index 0000000..66bbfb8 --- /dev/null +++ b/src/adapter/vy_load_config.ml @@ -0,0 +1,47 @@ +(* Adapter load_config + *) + +open Vyos1x + +let read_config filename = + let ch = open_in filename in + let s = really_input_string ch (in_channel_length ch) in + let ct = + try + Ok (Parser.from_string s) + with Vyos1x.Util.Syntax_error (opt, msg) -> + begin + match opt with + | None -> Error msg + | Some (line, pos) -> + let out = Printf.sprintf "%s line %d pos %d\n" msg line pos + in Error out + end + in + close_in ch; + ct + +let read_configs f g = + let l = read_config f in + let r = read_config g in + match l, r with + | Ok left, Ok right -> Ok (left, right) + | Error msg_l, Error msg_r -> Error (msg_l ^ msg_r) + | Error msg_l, _ -> Error msg_l + | _, Error msg_r -> Error msg_r + + +let args = [] +let usage = Printf.sprintf "Usage: %s <config> <new config>" Sys.argv.(0) + +let () = if Array.length Sys.argv <> 3 then (Arg.usage args usage; exit 1) + +let () = +let left_name = Sys.argv.(1) in +let right_name = Sys.argv.(2) in +let read = read_configs left_name right_name in +let res = + match read with + | Ok (left, right) -> Vyos1x_adapter.load_config left right + | Error msg -> msg +in Printf.printf "%s\n" res diff --git a/src/adapter/vy_set.ml b/src/adapter/vy_set.ml new file mode 100644 index 0000000..1fb29aa --- /dev/null +++ b/src/adapter/vy_set.ml @@ -0,0 +1,79 @@ +let legacy = ref false +let no_set = ref false +let valid = ref false +let output = ref "" +let path_opt = ref [] + +let usage = "Usage: " ^ Sys.argv.(0) ^ " [options]" + +let read_path p = + path_opt := p::!path_opt + +let speclist = [ + ("--legacy", Arg.Unit (fun _ -> legacy := true), "Use legacy validation"); + ("--no-set", Arg.Unit (fun _ -> no_set := true), "Do not set path"); + ] + +let format_out l = + let fl = List.filter (fun s -> (String.length s) > 0) l in + String.concat "\n\n" fl + +let is_valid v = + match v with + | None -> true + | Some _ -> false + +let valid_err v = + Option.value v ~default:"" + +let () = + let () = Arg.parse speclist read_path usage in + let path_list = List.rev !path_opt in + let () = + if List.length path_list = 0 then + (Printf.printf "no path specified\n"; exit 1) + in + let handle = + if !legacy || not !no_set then + let h = Vyos1x_adapter.cstore_handle_init () in + if not (Vyos1x_adapter.cstore_in_config_session_handle h) then + (Vyos1x_adapter.cstore_handle_free h; + Printf.printf "not in config session\n"; exit 1) + else Some h + else None + in + let valid = + if not !legacy then + Vyos1x_adapter.vyconf_validate_path path_list + else + begin + let out = + match handle with + | Some h -> Vyos1x_adapter.legacy_validate_path h path_list + | None -> "missing session handle" + in + match out with + | "" -> None + | _ -> Some out + end + in + let res = + if not !no_set && (is_valid valid) then + match handle with + | Some h -> + Vyos1x_adapter.cstore_set_path h path_list + | None -> "missing session handle" + else "" + in + let ret = + if (is_valid valid) && (res = "") then 0 + else 1 + in + let output = format_out [(valid_err valid); res] in + let () = + match handle with + | Some h -> Vyos1x_adapter.cstore_handle_free h + | None -> () + in + let () = print_endline output in + exit ret diff --git a/src/adapter/vyos1x_adapter.ml b/src/adapter/vyos1x_adapter.ml new file mode 100644 index 0000000..5835f5a --- /dev/null +++ b/src/adapter/vyos1x_adapter.ml @@ -0,0 +1,140 @@ +open Ctypes +open Foreign + +let libvyatta = Dl.dlopen ~flags:[Dl.RTLD_LAZY] ~filename:"libvyatta-cfg.so" + +let cstore_init = foreign ~from:libvyatta "vy_cstore_init" (void @-> returning uint64_t) +let cstore_free = foreign ~from:libvyatta "vy_cstore_free" (uint64_t @-> returning void) +let in_session = foreign ~from:libvyatta "vy_in_session" (uint64_t @-> returning int) +let cstore_set_path = foreign ~from:libvyatta "vy_set_path" (uint64_t @-> (ptr void) @-> size_t @-> returning string) +let cstore_del_path = foreign ~from:libvyatta "vy_delete_path" (uint64_t @-> (ptr void) @-> size_t @-> returning string) +let cstore_validate_path = foreign ~from:libvyatta "vy_validate_path" (uint64_t @-> (ptr void) @-> size_t @-> returning string) +let cstore_legacy_set_path = foreign ~from:libvyatta "vy_legacy_set_path" (uint64_t @-> (ptr void) @-> size_t @-> returning string) + +let cstore_handle_init () = Unsigned.UInt64.to_int (cstore_init ()) +let cstore_handle_free h = cstore_free (Unsigned.UInt64.of_int h) +let cstore_in_config_session_handle h = in_session (Unsigned.UInt64.of_int h) = 1 +let cstore_in_config_session () = cstore_in_config_session_handle (cstore_handle_init ()) + +let cstore_set_path handle path = + let len = List.length path in + let arr = CArray.of_list string path in + cstore_set_path (Unsigned.UInt64.of_int handle) (to_voidp (CArray.start arr)) (Unsigned.Size_t.of_int len) + +let legacy_validate_path handle path = + let len = List.length path in + let arr = CArray.of_list string path in + cstore_validate_path (Unsigned.UInt64.of_int handle) (to_voidp (CArray.start arr)) (Unsigned.Size_t.of_int len) + +let legacy_set_path handle path = + let len = List.length path in + let arr = CArray.of_list string path in + cstore_legacy_set_path (Unsigned.UInt64.of_int handle) (to_voidp (CArray.start arr)) (Unsigned.Size_t.of_int len) + +let cstore_delete_path handle path = + let len = List.length path in + let arr = CArray.of_list string path in + cstore_del_path (Unsigned.UInt64.of_int handle) (to_voidp (CArray.start arr)) (Unsigned.Size_t.of_int len) + +let set_path_reversed handle path _len = + let path = List.rev path in + cstore_set_path handle path + +let delete_path_reversed handle path _len = + let path = List.rev path in + cstore_delete_path handle path + +module VC = Client.Vyconf_client_session + +let get_sockname = + "/var/run/vyconfd.sock" + +let vyconf_validate_path path = + let socket = get_sockname in + let token = VC.session_init socket in + match token with + | Error e -> Some e + | Ok token -> + let out = VC.session_validate_path socket token path in + let _ = VC.session_free socket token in + match out with + | Ok _ -> None + | Error e -> Some e + +open Vyos1x + +module CT = Config_tree +module CD = Config_diff + +module ValueSet = Set.Make(String) + +let add_value handle acc out v = + let acc = v :: acc in + out ^ (set_path_reversed handle acc (List.length acc)) + +let add_values handle acc out vs = + match vs with + | [] -> out ^ (set_path_reversed handle acc (List.length acc)) + | _ -> List.fold_left (add_value handle acc) out vs + +let rec add_path handle acc out (node : CT.t) = + let acc = (Vytree.name_of_node node) :: acc in + let children = Vytree.children_of_node node in + match children with + | [] -> let data = Vytree.data_of_node node in + let values = data.values in + add_values handle acc out values + | _ -> List.fold_left (add_path handle acc) out children + +let del_value handle acc out v = + let acc = v :: acc in + out ^ (delete_path_reversed handle acc (List.length acc)) + +let del_values handle acc out vs = + match vs with + | [] -> out ^ (delete_path_reversed handle acc (List.length acc)) + | _ -> List.fold_left (del_value handle acc) out vs + +let del_path handle path out = + out ^ (cstore_delete_path handle path) + +(* +let update_data (CD.Diff_cstore data) m = + CD.Diff_cstore { data with out = m; } +*) + +let cstore_diff ?recurse:_ (path : string list) (CD.Diff_cstore res) (m : CD.change) = + let handle = res.handle in + match m with + | Added -> let node = Vytree.get res.right path in + let acc = List.tl (List.rev path) in + CD.Diff_cstore { res with out = add_path handle acc res.out node } + | Subtracted -> CD.Diff_cstore { res with out = del_path handle path res.out } + | Unchanged -> CD.Diff_cstore (res) + | Updated v -> + let ov = CT.get_values res.left path in + let acc = List.rev path in + match ov, v with + | [x], [y] -> let out = del_value handle acc res.out x in + let out = add_value handle acc out y in + CD.Diff_cstore { res with out = out } + | _, _ -> let ov_set = ValueSet.of_list ov in + let v_set = ValueSet.of_list v in + let sub_vals = ValueSet.elements (ValueSet.diff ov_set v_set) in + let add_vals = ValueSet.elements (ValueSet.diff v_set ov_set) in + let out = del_values handle acc res.out sub_vals in + let out = add_values handle acc out add_vals in + CD.Diff_cstore { res with out = out } + +let load_config left right = + let h = cstore_handle_init () in + if not (cstore_in_config_session_handle h) then + (cstore_handle_free h; + let out = "not in config session\n" in + out) + else + let dcstore = CD.make_diff_cstore left right h in + let dcstore = CD.diff [] cstore_diff dcstore (Option.some left, Option.some right) in + let ret = CD.eval_result dcstore in + cstore_handle_free h; + ret.out diff --git a/src/adapter/vyos1x_adapter.mli b/src/adapter/vyos1x_adapter.mli new file mode 100644 index 0000000..cb40e2b --- /dev/null +++ b/src/adapter/vyos1x_adapter.mli @@ -0,0 +1,16 @@ +open Vyos1x + +val cstore_handle_init : unit -> int +val cstore_handle_free : int -> unit +val cstore_in_config_session_handle : int -> bool +val cstore_in_config_session : unit -> bool +val cstore_set_path : int -> string list -> string +val legacy_validate_path : int -> string list -> string +val legacy_set_path : int -> string list -> string +val cstore_delete_path : int -> string list -> string +val set_path_reversed : int -> string list -> int -> string +val delete_path_reversed : int -> string list -> int -> string + +val vyconf_validate_path : string list -> string option + +val load_config : Config_tree.t -> Config_tree.t -> string -- cgit v1.2.3 From 7c093d7465438590ebcf142557f357762ab17698 Mon Sep 17 00:00:00 2001 From: John Estabrook <jestabro@vyos.io> Date: Thu, 24 Oct 2024 13:35:36 -0500 Subject: T6718: read argv explicity instead of using Arg The standard package Arg is understandably confused by paths such as: interfaces openvpn vtun0 openvpn-option --persist-tun Collect args from Sys.argv and use env vars for debug options. --- src/adapter/vy_delete.ml | 14 ++------------ src/adapter/vy_set.ml | 36 +++++++++++++++++------------------- 2 files changed, 19 insertions(+), 31 deletions(-) (limited to 'src/adapter') diff --git a/src/adapter/vy_delete.ml b/src/adapter/vy_delete.ml index 652fdad..304e74b 100644 --- a/src/adapter/vy_delete.ml +++ b/src/adapter/vy_delete.ml @@ -1,16 +1,6 @@ -let path_opt = ref [] - -let usage = "Usage: " ^ Sys.argv.(0) ^ " [options]" - -let read_path p = - path_opt := p::!path_opt - -let speclist = [ - ] - let () = - let () = Arg.parse speclist read_path usage in - let path_list = List.rev !path_opt in + let path_list = Array.to_list (Array.sub Sys.argv 1 (Array.length Sys.argv - 1)) + in let () = if List.length path_list = 0 then (Printf.printf "no path specified\n"; exit 1) diff --git a/src/adapter/vy_set.ml b/src/adapter/vy_set.ml index 1fb29aa..b631de0 100644 --- a/src/adapter/vy_set.ml +++ b/src/adapter/vy_set.ml @@ -1,18 +1,4 @@ -let legacy = ref false -let no_set = ref false let valid = ref false -let output = ref "" -let path_opt = ref [] - -let usage = "Usage: " ^ Sys.argv.(0) ^ " [options]" - -let read_path p = - path_opt := p::!path_opt - -let speclist = [ - ("--legacy", Arg.Unit (fun _ -> legacy := true), "Use legacy validation"); - ("--no-set", Arg.Unit (fun _ -> no_set := true), "Do not set path"); - ] let format_out l = let fl = List.filter (fun s -> (String.length s) > 0) l in @@ -27,14 +13,26 @@ let valid_err v = Option.value v ~default:"" let () = - let () = Arg.parse speclist read_path usage in - let path_list = List.rev !path_opt in + let path_list = Array.to_list (Array.sub Sys.argv 1 (Array.length Sys.argv - 1)) + in let () = if List.length path_list = 0 then (Printf.printf "no path specified\n"; exit 1) in + let legacy = + try + let _ = Sys.getenv "LEGACY_VALIDATE" in + true + with Not_found -> false + in + let no_set = + try + let _ = Sys.getenv "LEGACY_NO_SET" in + true + with Not_found -> false + in let handle = - if !legacy || not !no_set then + if legacy || not no_set then let h = Vyos1x_adapter.cstore_handle_init () in if not (Vyos1x_adapter.cstore_in_config_session_handle h) then (Vyos1x_adapter.cstore_handle_free h; @@ -43,7 +41,7 @@ let () = else None in let valid = - if not !legacy then + if not legacy then Vyos1x_adapter.vyconf_validate_path path_list else begin @@ -58,7 +56,7 @@ let () = end in let res = - if not !no_set && (is_valid valid) then + if not no_set && (is_valid valid) then match handle with | Some h -> Vyos1x_adapter.cstore_set_path h path_list -- cgit v1.2.3