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