mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-07 09:04:21 +00:00
doc: Update documentation for new api
Signed-off-by: Donald Lee <dlqs@gmx.com>
This commit is contained in:
parent
555f7625a8
commit
951f084976
@ -135,24 +135,20 @@ A typical execution call looks something like this:
|
||||
int status_ok = 0, status_fail = 1;
|
||||
struct prefix p = ...;
|
||||
|
||||
struct frrscript_env env[] = {
|
||||
{"integer", "STATUS_FAIL", &status_fail},
|
||||
{"integer", "STATUS_OK", &status_ok},
|
||||
{"prefix", "myprefix", &p},
|
||||
{}};
|
||||
|
||||
int result = frrscript_call(fs, env);
|
||||
int result = frrscript_call(fs,
|
||||
("STATUS_FAIL", &status_fail),
|
||||
("STATUS_OK", &status_ok),
|
||||
("prefix", &p));
|
||||
|
||||
|
||||
To execute a loaded script, we need to define the inputs. These inputs are
|
||||
passed by binding values to variable names that will be accessible within the
|
||||
passed in by binding values to variable names that will be accessible within the
|
||||
Lua environment. Basically, all communication with the script takes place via
|
||||
global variables within the script, and to provide inputs we predefine globals
|
||||
before the script runs. This is done by passing ``frrscript_call()`` an array
|
||||
of ``struct frrscript_env``. Each struct has three fields. The first identifies
|
||||
the type of the value being passed; more on this later. The second defines the
|
||||
name of the global variable within the script environment to bind the third
|
||||
argument (the value) to.
|
||||
before the script runs. This is done by passing ``frrscript_call()`` a list of
|
||||
parenthesized pairs, where the first and second fields identify, respectively,
|
||||
the name of the global variable within the script environment and the value it
|
||||
is bound to.
|
||||
|
||||
The script is then executed and returns a general status code. In the success
|
||||
case this will be 0, otherwise it will be nonzero. The script itself does not
|
||||
@ -162,32 +158,10 @@ determine this code, it is provided by the Lua interpreter.
|
||||
Querying State
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
When a chunk is executed, its state at exit is preserved and can be inspected.
|
||||
.. todo::
|
||||
|
||||
After running a script, results may be retrieved by querying the script's
|
||||
state. Again this is done by retrieving the values of global variables, which
|
||||
are known to the script author to be "output" variables.
|
||||
|
||||
A result is retrieved like so:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript_env myresult = {"string", "myresult"};
|
||||
|
||||
char *myresult = frrscript_get_result(fs, &myresult);
|
||||
|
||||
... do something ...
|
||||
|
||||
XFREE(MTYPE_TMP, myresult);
|
||||
|
||||
|
||||
As with arguments, results are retrieved by providing a ``struct
|
||||
frrscript_env`` specifying a type and a global name. No value is necessary, nor
|
||||
is it modified by ``frrscript_get_result()``. That function simply extracts the
|
||||
requested value from the script state and returns it.
|
||||
|
||||
In most cases the returned value will be allocated with ``MTYPE_TMP`` and will
|
||||
need to be freed after use.
|
||||
This section will be updated once ``frrscript_get_result`` has been
|
||||
updated to work with the new ``frrscript_call`` and the rest of the new API.
|
||||
|
||||
|
||||
Unloading
|
||||
@ -199,21 +173,14 @@ To destroy a script and its associated state:
|
||||
|
||||
frrscript_unload(fs);
|
||||
|
||||
Values returned by ``frrscript_get_result`` are still valid after the script
|
||||
they were retrieved from is unloaded.
|
||||
|
||||
Note that you must unload and then load the script if you want to reset its
|
||||
state, for example to run it again with different inputs. Otherwise the state
|
||||
from the previous run carries over into subsequent runs.
|
||||
|
||||
|
||||
.. _marshalling:
|
||||
|
||||
Marshalling
|
||||
^^^^^^^^^^^
|
||||
|
||||
Earlier sections glossed over the meaning of the type name field in ``struct
|
||||
frrscript_env`` and how data is passed between C and Lua. Lua, as a dynamically
|
||||
Earlier sections glossed over the types of values that can be passed into
|
||||
``frrscript_call`` and how data is passed between C and Lua. Lua, as a dynamically
|
||||
typed, garbage collected language, cannot directly use C values without some
|
||||
kind of marshalling / unmarshalling system to translate types between the two
|
||||
runtimes.
|
||||
@ -222,31 +189,10 @@ Lua communicates with C code using a stack. C code wishing to provide data to
|
||||
Lua scripts must provide a function that marshalls the C data into a Lua
|
||||
representation and pushes it on the stack. C code wishing to retrieve data from
|
||||
Lua must provide a corresponding unmarshalling function that retrieves a Lua
|
||||
value from the stack and converts it to the corresponding C type. These two
|
||||
functions, together with a chosen name of the type they operate on, are
|
||||
referred to as ``codecs`` in FRR.
|
||||
value from the stack and converts it to the corresponding C type. These
|
||||
functions are known as encoders and decoders in FRR.
|
||||
|
||||
A codec is defined as:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef void (*encoder_func)(lua_State *, const void *);
|
||||
typedef void *(*decoder_func)(lua_State *, int);
|
||||
|
||||
struct frrscript_codec {
|
||||
const char *typename;
|
||||
encoder_func encoder;
|
||||
decoder_func decoder;
|
||||
};
|
||||
|
||||
A typename string and two function pointers.
|
||||
|
||||
``typename`` can be anything you want. For example, for the combined types of
|
||||
``struct prefix`` and its equivalent in Lua I have chosen the name ``prefix``.
|
||||
There is no restriction on naming here, it is just a human name used as a key
|
||||
and specified when passing and retrieving values.
|
||||
|
||||
``encoder`` is a function that takes a ``lua_State *`` and a C type and pushes
|
||||
An encoder is a function that takes a ``lua_State *`` and a C type and pushes
|
||||
onto the Lua stack a value representing the C type. For C structs, the usual
|
||||
case, this will typically be a Lua table (tables are the only datastructure Lua
|
||||
has). For example, here is the encoder function for ``struct prefix``:
|
||||
@ -254,7 +200,7 @@ has). For example, here is the encoder function for ``struct prefix``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lua_pushprefix(lua_State *L, const struct prefix *prefix)
|
||||
void lua_pushprefix(lua_State *L, struct prefix *prefix)
|
||||
{
|
||||
char buffer[PREFIX_STRLEN];
|
||||
|
||||
@ -269,17 +215,47 @@ has). For example, here is the encoder function for ``struct prefix``:
|
||||
lua_setfield(L, -2, "family");
|
||||
}
|
||||
|
||||
This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is:
|
||||
This function pushes a single value onto the Lua stack. It is a table whose
|
||||
equivalent in Lua is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
{ ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
|
||||
|
||||
|
||||
``decoder`` does the reverse; it takes a ``lua_State *`` and an index into the
|
||||
stack, and unmarshalls a Lua value there into the corresponding C type. Again
|
||||
for ``struct prefix``:
|
||||
Decoders are a bit more involved. They do the reverse; a decoder function takes
|
||||
a ``lua_State *``, pops a value off the Lua stack and converts it back into its
|
||||
C type.
|
||||
However, since Lua programs have the ability to directly modify their inputs
|
||||
(i.e. values passed in via ``frrscript_call``), we need two separate decoder
|
||||
functions, called ``lua_decode_*`` and ``lua_to*``.
|
||||
|
||||
A ``lua_decode_*`` function takes a ``lua_State*``, an index, and a C type, and
|
||||
unmarshalls a Lua value into that C type.
|
||||
Again, for ``struct prefix``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lua_decode_prefix(lua_State *L, int idx, struct prefix *prefix)
|
||||
{
|
||||
lua_getfield(L, idx, "network");
|
||||
(void)str2prefix(lua_tostring(L, -1), prefix);
|
||||
lua_pop(L, 1);
|
||||
/* pop the table */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
.. warning::
|
||||
``lua_decode_prefix`` functions should leave the Lua stack completely empty
|
||||
when they return.
|
||||
For decoders that unmarshall fields from tables, remember to pop the table
|
||||
at the end.
|
||||
|
||||
|
||||
A ``lua_to*`` function perform a similar role except that it first allocates
|
||||
memory for the new C type before decoding the value from the Lua stack, then
|
||||
returns a pointer to the newly allocated C type.
|
||||
This function can and should be implemented using ``lua_decode_*``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -287,39 +263,66 @@ for ``struct prefix``:
|
||||
{
|
||||
struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
|
||||
|
||||
lua_getfield(L, idx, "network");
|
||||
str2prefix(lua_tostring(L, -1), p);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_decode_prefix(L, idx, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
By convention these functions should be called ``lua_to*``, as this is the
|
||||
naming convention used by the Lua C library for the basic types e.g.
|
||||
``lua_tointeger`` and ``lua_tostring``.
|
||||
|
||||
The returned data must always be copied off the stack and the copy must be
|
||||
allocated with ``MTYPE_TMP``. This way it is possible to unload the script
|
||||
(destroy the state) without invalidating any references to values stored in it.
|
||||
Note that it is the caller's responsibility to free the data.
|
||||
|
||||
To register a new type with its corresponding encoding functions:
|
||||
For consistency, we should always name functions of the first type
|
||||
``lua_decode_*``.
|
||||
Functions of the second type should be named ``lua_to*``, as this is the
|
||||
naming convention used by the Lua C library for the basic types e.g.
|
||||
``lua_tointeger`` and ``lua_tostring``.
|
||||
|
||||
This two-function design allows the compiler to warn if a value passed into
|
||||
``frrscript_call`` does not have a encoder and decoder for that type.
|
||||
The ``lua_to*`` functions enable us to easily create decoders for nested
|
||||
structures.
|
||||
|
||||
To register a new type with its corresponding encoding and decoding functions,
|
||||
add the mapping in the following macros in ``frrscript.h``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript_codec frrscript_codecs_lib[] = {
|
||||
{.typename = "prefix",
|
||||
.encoder = (encoder_func)lua_pushprefix,
|
||||
.decoder = lua_toprefix},
|
||||
{.typename = "sockunion",
|
||||
.encoder = (encoder_func)lua_pushsockunion,
|
||||
.decoder = lua_tosockunion},
|
||||
...
|
||||
{}};
|
||||
#define ENCODE_ARGS_WITH_STATE(L, value) \
|
||||
_Generic((value), \
|
||||
...
|
||||
struct prefix * : lua_pushprefix, \
|
||||
)(L, value)
|
||||
|
||||
frrscript_register_type_codecs(frrscript_codecs_lib);
|
||||
#define DECODE_ARGS_WITH_STATE(L, value) \
|
||||
_Generic((value), \
|
||||
...
|
||||
struct prefix * : lua_decode_prefix, \
|
||||
)(L, -1, value)
|
||||
|
||||
|
||||
At compile time, the compiler will search for encoders/decoders for the type of
|
||||
each value passed in via ``frrscript_call``. If a encoder/decoder cannot be
|
||||
found, it will appear as a compile warning. Note that the types must
|
||||
match *exactly*.
|
||||
In the above example, we defined encoders/decoders for a value of
|
||||
``struct prefix *``, but not ``struct prefix`` or ``const struct prefix *``.
|
||||
|
||||
``const`` values are a special case. We want to use them in our Lua scripts
|
||||
but not modify them, so creating a decoder for them would be meaningless.
|
||||
But we still need a decoder for the type of value so that the compiler will be
|
||||
satisfied.
|
||||
For that, use ``lua_decode_noop``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define DECODE_ARGS_WITH_STATE(L, value) \
|
||||
_Generic((value), \
|
||||
...
|
||||
const struct prefix * : lua_decode_noop, \
|
||||
)(L, -1, value)
|
||||
|
||||
From this point on the type names are available to be used when calling any
|
||||
script and getting its results.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user