mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 09:18:53 +00:00
doc: Update documentation
Signed-off-by: Donald Lee <dlqs@gmx.com>
This commit is contained in:
parent
64d457d7ac
commit
aed6f883a0
@ -14,8 +14,8 @@ is implemented using the standard Lua C bindings. The supported version of Lua
|
||||
is 5.3.
|
||||
|
||||
C objects may be passed into Lua and Lua objects may be retrieved by C code via
|
||||
a marshalling system. In this way, arbitrary data from FRR may be passed to
|
||||
scripts. It is possible to pass C functions as well.
|
||||
a encoding/decoding system. In this way, arbitrary data from FRR may be passed to
|
||||
scripts.
|
||||
|
||||
The Lua environment is isolated from the C environment; user scripts cannot
|
||||
access FRR's address space unless explicitly allowed by FRR.
|
||||
@ -53,150 +53,290 @@ Reasons against supporting multiple scripting languages:
|
||||
with which a given script can be shared
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
-------
|
||||
|
||||
FRR's concept of a script is somewhat abstracted away from the fact that it is
|
||||
Lua underneath. A script in has two things:
|
||||
|
||||
- name
|
||||
- state
|
||||
|
||||
In code:
|
||||
FRR's scripting functionality is provided in the form of Lua functions in Lua
|
||||
scripts (``.lua`` files). One Lua script may contain many Lua functions. These
|
||||
are respectively encapsulated in the following structures:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript {
|
||||
/* Script name */
|
||||
char *name;
|
||||
/* Lua file name */
|
||||
char *name;
|
||||
|
||||
/* Lua state */
|
||||
struct lua_State *L;
|
||||
/* hash of lua_function_states */
|
||||
struct hash *lua_function_hash;
|
||||
};
|
||||
|
||||
struct lua_function_state {
|
||||
/* Lua function name */
|
||||
char *name;
|
||||
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
|
||||
``name`` is simply a string. Everything else is in ``state``, which is itself a
|
||||
Lua library object (``lua_State``). This is an opaque struct that is
|
||||
manipulated using ``lua_*`` functions. The basic ones are imported from
|
||||
``lua.h`` and the rest are implemented within FRR to fill our use cases. The
|
||||
thing to remember is that all operations beyond the initial loading the script
|
||||
take place on this opaque state object.
|
||||
`struct frrscript`: Since all Lua functions are contained within scripts, the
|
||||
following APIs manipulates this structure. ``name`` contains the
|
||||
Lua script name and a hash of Lua functions to their function names.
|
||||
|
||||
There are four basic actions that can be done on a script:
|
||||
`struct lua_function_state` is an internal structure, but it essentially contains
|
||||
the name of the Lua function and its state (a stack), which is run using Lua
|
||||
library functions.
|
||||
|
||||
- load
|
||||
- execute
|
||||
- query state
|
||||
- unload
|
||||
In general, to run a Lua function, these steps must take place:
|
||||
|
||||
They are typically done in this order.
|
||||
- Initialization
|
||||
- Load
|
||||
- Call
|
||||
- Delete
|
||||
|
||||
|
||||
Loading
|
||||
^^^^^^^
|
||||
|
||||
A snippet of Lua code is referred to as a "chunk". These are simply text. FRR
|
||||
presently assumes chunks are located in individual files specific to one task.
|
||||
These files are stored in the scripts directory and must end in ``.lua``.
|
||||
|
||||
A script object is created by loading a script. This is done with
|
||||
``frrscript_load()``. This function takes the name of the script and an
|
||||
optional callback function. The string ".lua" is appended to the script name,
|
||||
and the resultant filename is looked for in the scripts directory.
|
||||
|
||||
For example, to load ``/etc/frr/scripts/bingus.lua``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript *fs = frrscript_load("bingus", NULL);
|
||||
|
||||
During loading the script is validated for syntax and its initial environment
|
||||
is setup. By default this does not include the Lua standard library; there are
|
||||
security issues to consider, though for practical purposes untrusted users
|
||||
should not be able to write the scripts directory anyway. If desired the Lua
|
||||
standard library may be added to the script environment using
|
||||
``luaL_openlibs(fs->L)`` after loading the script. Further information on
|
||||
setting up the script environment is in the Lua manual.
|
||||
|
||||
|
||||
Executing
|
||||
^^^^^^^^^
|
||||
|
||||
After loading, scripts may be executed. A script may take input in the form of
|
||||
variable bindings set in its environment prior to being run, and may provide
|
||||
results by setting the value of variables. Arbitrary C values may be
|
||||
transferred into the script environment, including functions.
|
||||
|
||||
A typical execution call looks something like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript *fs = frrscript_load(...);
|
||||
|
||||
int status_ok = 0, status_fail = 1;
|
||||
struct prefix p = ...;
|
||||
|
||||
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 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()`` 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
|
||||
determine this code, it is provided by the Lua interpreter.
|
||||
|
||||
|
||||
Querying State
|
||||
Initialization
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. todo::
|
||||
The ``frrscript`` object encapsulates the Lua function state(s) from
|
||||
one Lua script file. To create, use ``frrscript_new()`` which takes the
|
||||
name of the Lua script.
|
||||
The string ".lua" is appended to the script name, and the resultant filename
|
||||
will be used to look for the script when we want to load a Lua function from it.
|
||||
|
||||
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
|
||||
^^^^^^^^^
|
||||
|
||||
To destroy a script and its associated state:
|
||||
For example, to create ``frrscript`` for ``/etc/frr/scripts/bingus.lua``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
frrscript_unload(fs);
|
||||
struct frrscript *fs = frrscript_new("bingus");
|
||||
|
||||
|
||||
.. _marshalling:
|
||||
The script is *not* read at this stage.
|
||||
This function cannot be used to test for a script's presence.
|
||||
|
||||
Marshalling
|
||||
^^^^^^^^^^^
|
||||
Load
|
||||
^^^^
|
||||
|
||||
The function to be called must first be loaded. Use ``frrscript_load()``
|
||||
which takes a ``frrscript`` object, the name of the Lua function
|
||||
and a callback function.
|
||||
|
||||
For example, to load the Lua function ``on_foo``
|
||||
in ``/etc/frr/scripts/bingus.lua``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int ret = frrscript_load(fs, "on_foo", NULL);
|
||||
|
||||
|
||||
This function returns 0 if and only if the Lua function was successfully loaded.
|
||||
A non-zero return could indicate either a missing Lua script, a missing
|
||||
Lua function, or an error when loading the function.
|
||||
|
||||
During loading the script is validated for syntax and its environment
|
||||
is set up. By default this does not include the Lua standard library; there are
|
||||
security issues to consider, though for practical purposes untrusted users
|
||||
should not be able to write the scripts directory anyway.
|
||||
|
||||
Call
|
||||
^^^^
|
||||
|
||||
After loading, Lua functions may be called.
|
||||
|
||||
Input
|
||||
"""""
|
||||
|
||||
Inputs to the Lua script should be given by providing a list of parenthesized
|
||||
pairs,
|
||||
where the first and second field identify the name of the variable and the
|
||||
value it is bound to, respectively.
|
||||
The types of the values must have registered encoders (more below); the compiler
|
||||
will warn you otherwise.
|
||||
|
||||
These variables are first encoded in-order, then provided as arguments
|
||||
to the Lua function. In the example, note that ``c`` is passed in as a value
|
||||
while ``a`` and ``b`` are passed in as pointers.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int a = 100, b = 200, c = 300;
|
||||
frrscript_call(fs, "on_foo", ("a", &a), ("b", &b), ("c", c));
|
||||
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
function on_foo(a, b, c)
|
||||
-- a is 100, b is 200, c is 300
|
||||
...
|
||||
|
||||
|
||||
Output
|
||||
""""""
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int a = 100, b = 200, c = 300;
|
||||
frrscript_call(fs, "on_foo", ("a", &a), ("b", &b), ("c", c));
|
||||
// a is 500, b is 200, c is 300
|
||||
|
||||
int* d = frrscript_get_result(fs, "on_foo", "d", lua_tointegerp);
|
||||
// d is 800
|
||||
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
function on_foo(a, b, c)
|
||||
b = 600
|
||||
return { ["a"] = 500, ["c"] = 700, ["d"] = 800 }
|
||||
end
|
||||
|
||||
|
||||
**Lua functions being called must return a single table of string names to
|
||||
values.**
|
||||
(Lua functions should return an empty table if there is no output.)
|
||||
The keys of the table are mapped back to names of variables in C. Note that
|
||||
the values in the table can also be tables. Since tables are Lua's primary
|
||||
data structure, this design lets us return any Lua value.
|
||||
|
||||
After the Lua function returns, the names of variables to ``frrscript_call()``
|
||||
are matched against keys of the returned table, and then decoded. The types
|
||||
being decoded must have registered decoders (more below); the compiler will
|
||||
warn you otherwise.
|
||||
|
||||
In the example, since ``a`` was in the returned table and ``b`` was not,
|
||||
``a`` was decoded and its value modified, while ``b`` was not decoded.
|
||||
``c`` was decoded as well, but its decoder is a noop.
|
||||
What modifications happen given a variable depends whether its name was
|
||||
in the returned table and the decoder's implementation.
|
||||
|
||||
.. warning::
|
||||
Always keep in mind that non const-qualified pointers in
|
||||
``frrscript_call()`` may be modified - this may be a source of bugs.
|
||||
On the other hand, const-qualified pointers and other values cannot
|
||||
be modified.
|
||||
|
||||
|
||||
.. tip::
|
||||
You can make a copy of a data structure and pass that in instead,
|
||||
so that modifications only happen to that copy.
|
||||
|
||||
``frrscript_call()`` returns 0 if and only if the Lua function was successfully
|
||||
called. A non-zero return could indicate either a missing Lua script, a missing
|
||||
Lua function, or an error from the Lua interpreter.
|
||||
|
||||
In the above example, ``d`` was not an input to ``frrscript_call()``, so its
|
||||
value must be explicitly retrieved with ``frrscript_get_result``.
|
||||
|
||||
``frrscript_get_result()`` takes a
|
||||
decoder and string name which is used as a key to search the returned table.
|
||||
Returns the pointer to the decoded value, or NULL if it was not found.
|
||||
In the example, ``d`` is a "new" value in C space,
|
||||
so memory allocation might take place. Hence the caller is
|
||||
responsible for memory deallocation.
|
||||
|
||||
|
||||
Delete
|
||||
^^^^^^
|
||||
|
||||
To delete a script and the all Lua states associated with it:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
frrscript_delete(fs);
|
||||
|
||||
|
||||
A complete example
|
||||
""""""""""""""""""
|
||||
|
||||
So, a typical exection call, with error checking, looks something like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct frrscript *fs = frrscript_new("my_script"); // name *without* .lua
|
||||
|
||||
int ret = frrscript_load(fs, "on_foo", NULL);
|
||||
if (ret != 0)
|
||||
goto DONE; // Lua script or function might have not been found
|
||||
|
||||
int a = 100, b = 200, c = 300;
|
||||
ret = frrscript_call(fs, "on_foo", ("a", &a), ("b", &b), ("c", c));
|
||||
if (ret != 0)
|
||||
goto DONE; // Lua function might have not successfully run
|
||||
|
||||
// a and b might be modified
|
||||
assert(a == 500);
|
||||
assert(b == 200);
|
||||
|
||||
// c could not have been modified
|
||||
assert(c == 300);
|
||||
|
||||
// d is new
|
||||
int* d = frrscript_get_result(fs, "on_foo", "d", lua_tointegerp);
|
||||
|
||||
if (!d)
|
||||
goto DONE; // "d" might not have been in returned table
|
||||
|
||||
assert(*d == 800);
|
||||
XFREE(MTYPE_TMP, d); // caller responsible for free
|
||||
|
||||
DONE:
|
||||
frrscript_delete(fs);
|
||||
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
function on_foo(a, b, c)
|
||||
b = 600
|
||||
return { a = 500, c = 700, d = 800 }
|
||||
end
|
||||
|
||||
|
||||
Note that ``{ a = ...`` is same as ``{ ["a"] = ...``; it is Lua shorthand to
|
||||
use the variable name as the key in a table.
|
||||
|
||||
Encoding and Decoding
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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.
|
||||
``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 encoding / decoding system to
|
||||
translate types between the two runtimes.
|
||||
|
||||
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
|
||||
Lua scripts must provide a function that encodes 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
|
||||
functions are known as encoders and decoders in FRR.
|
||||
Lua must provide a corresponding decoder function that retrieves a Lua
|
||||
value from the stack and converts it to the corresponding C type.
|
||||
|
||||
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``:
|
||||
Encoders and decoders are provided for common data types.
|
||||
Developers wishing to pass their own data structures between C and Lua need to
|
||||
create encoders and decoders for that data type.
|
||||
|
||||
We try to keep them named consistently.
|
||||
There are three kinds of encoders and decoders:
|
||||
|
||||
1. lua_push*: encodes a value onto the Lua stack.
|
||||
Required for ``frrscript_call``.
|
||||
|
||||
2. lua_decode*: decodes a value from the Lua stack.
|
||||
Required for ``frrscript_call``.
|
||||
Only non const-qualified pointers may be actually decoded (more below).
|
||||
|
||||
3. lua_to*: allocates memory and decodes a value from the Lua stack.
|
||||
Required for ``frrscript_get_result``.
|
||||
|
||||
This design allows us to combine typesafe *modification* of C values as well as
|
||||
*allocation* of new C values.
|
||||
|
||||
In the following sections, we will use the encoders/decoders for ``struct prefix`` as an example.
|
||||
|
||||
Encoding
|
||||
""""""""
|
||||
|
||||
An encoder function takes a ``lua_State *``, a C type and pushes that value onto
|
||||
the Lua state (a stack).
|
||||
For C structs, the usual case,
|
||||
this will typically be encoded to a Lua table, then pushed onto the Lua stack.
|
||||
|
||||
Here is the encoder function for ``struct prefix``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -204,8 +344,6 @@ has). For example, here is the encoder function for ``struct prefix``:
|
||||
{
|
||||
char buffer[PREFIX_STRLEN];
|
||||
|
||||
zlog_debug("frrlua: pushing prefix table");
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
|
||||
lua_setfield(L, -2, "network");
|
||||
@ -215,7 +353,7 @@ 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
|
||||
This function pushes a single value, a table, onto the Lua stack, whose
|
||||
equivalent in Lua is:
|
||||
|
||||
.. code-block:: c
|
||||
@ -223,16 +361,23 @@ equivalent in Lua is:
|
||||
{ ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
|
||||
|
||||
|
||||
Decoding
|
||||
""""""""
|
||||
|
||||
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``:
|
||||
There are two: ``lua_decode*`` and ``lua_to*``. The former does no mememory
|
||||
allocation and is needed for ``frrscript_call``.
|
||||
The latter performs allocation and is optional.
|
||||
|
||||
A ``lua_decode_*`` function takes a ``lua_State*``, an index, and a pointer
|
||||
to a C data structure, and directly modifies the structure with values from the
|
||||
Lua stack. Note that only non const-qualified pointers may be modified;
|
||||
``lua_decode_*`` for other types will be noops.
|
||||
|
||||
Again, for ``struct prefix *``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -240,22 +385,45 @@ Again, for ``struct prefix``:
|
||||
{
|
||||
lua_getfield(L, idx, "network");
|
||||
(void)str2prefix(lua_tostring(L, -1), prefix);
|
||||
/* pop the netork string */
|
||||
lua_pop(L, 1);
|
||||
/* pop the table */
|
||||
/* pop the prefix table */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
Note:
|
||||
- Before ``lua_decode*`` is run, the "prefix" table is already on the top of
|
||||
the stack. ``frrscript_call`` does this for us.
|
||||
- However, at the end of ``lua_decode*``, the "prefix" table should be popped.
|
||||
- The other two fields in the "network" table are disregarded, meaning that any
|
||||
modification to them is discarded in C space. In this case, this is desired
|
||||
behavior.
|
||||
|
||||
.. 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.
|
||||
``lua_decode*`` functions should pop all values that ``lua_to*`` pushed onto
|
||||
the Lua stack.
|
||||
For encoders that pushed a table, its decoder should pop the table at the end.
|
||||
The above is an example.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
``int`` is not a non const-qualified pointer, so for ``int``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void lua_decode_int_noop(lua_State *L, int idx, int i)
|
||||
{ //noop
|
||||
}
|
||||
|
||||
|
||||
A ``lua_to*`` function provides identical functionality 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. You only need to implement
|
||||
this function to use with ``frrscript_get_result`` to retrieve a result of
|
||||
this type.
|
||||
|
||||
This function can and should be implemented using ``lua_decode_*``:
|
||||
|
||||
.. code-block:: c
|
||||
@ -274,18 +442,11 @@ 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.
|
||||
|
||||
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.
|
||||
Registering encoders and decoders for frrscript_call
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
To register a new type with its corresponding encoding and decoding functions,
|
||||
To register a new type with its ``lua_push*`` and ``lua_decode*`` functions,
|
||||
add the mapping in the following macros in ``frrscript.h``:
|
||||
|
||||
.. code-block:: diff
|
||||
@ -331,11 +492,12 @@ For that, use ``lua_decode_noop``:
|
||||
|
||||
.. note::
|
||||
|
||||
Marshalled types are not restricted to simple values like integers, strings
|
||||
and tables. It is possible to marshall a type such that the resultant object
|
||||
in Lua is an actual object-oriented object, complete with methods that call
|
||||
back into defined C functions. See the Lua manual for how to do this; for a
|
||||
code example, look at how zlog is exported into the script environment.
|
||||
Encodable/decodable types are not restricted to simple values like integers,
|
||||
strings and tables.
|
||||
It is possible to encode a type such that the resultant object in Lua
|
||||
is an actual object-oriented object, complete with methods that call
|
||||
back into defined C functions. See the Lua manual for how to do this;
|
||||
for a code example, look at how zlog is exported into the script environment.
|
||||
|
||||
|
||||
Script Environment
|
||||
@ -364,10 +526,11 @@ Examples
|
||||
For a complete code example involving passing custom types, retrieving results,
|
||||
and doing complex calculations in Lua, look at the implementation of the
|
||||
``match script SCRIPT`` command for BGP routemaps. This example calls into a
|
||||
script with a route prefix and attributes received from a peer and expects the
|
||||
script to return a match / no match / match and update result.
|
||||
script with a function named ``route_match``,
|
||||
provides route prefix and attributes received from a peer and expects the
|
||||
function to return a match / no match / match and update result.
|
||||
|
||||
An example script to use with this follows. This script matches, does not match
|
||||
An example script to use with this follows. This function matches, does not match
|
||||
or updates a route depending on how many BGP UPDATE messages the peer has
|
||||
received when the script is called, simply as a demonstration of what can be
|
||||
accomplished with scripting.
|
||||
@ -378,64 +541,75 @@ accomplished with scripting.
|
||||
-- Example route map matching
|
||||
-- author: qlyoung
|
||||
--
|
||||
-- The following variables are available to us:
|
||||
-- The following variables are available in the global environment:
|
||||
-- log
|
||||
-- logging library, with the usual functions
|
||||
-- prefix
|
||||
--
|
||||
-- route_match arguments:
|
||||
-- table prefix
|
||||
-- the route under consideration
|
||||
-- attributes
|
||||
-- table attributes
|
||||
-- the route's attributes
|
||||
-- peer
|
||||
-- table peer
|
||||
-- the peer which received this route
|
||||
-- RM_FAILURE
|
||||
-- integer RM_FAILURE
|
||||
-- status code in case of failure
|
||||
-- RM_NOMATCH
|
||||
-- integer RM_NOMATCH
|
||||
-- status code for no match
|
||||
-- RM_MATCH
|
||||
-- integer RM_MATCH
|
||||
-- status code for match
|
||||
-- RM_MATCH_AND_CHANGE
|
||||
-- integer RM_MATCH_AND_CHANGE
|
||||
-- status code for match-and-set
|
||||
--
|
||||
-- We need to set the following out values:
|
||||
-- action
|
||||
-- Set to the appropriate status code to indicate what we did
|
||||
-- attributes
|
||||
-- Setting fields on here will propagate them back up to the caller if
|
||||
-- 'action' is set to RM_MATCH_AND_CHANGE.
|
||||
|
||||
|
||||
log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string)
|
||||
|
||||
function on_match (prefix, attrs)
|
||||
log.info("Match")
|
||||
action = RM_MATCH
|
||||
end
|
||||
|
||||
function on_nomatch (prefix, attrs)
|
||||
log.info("No match")
|
||||
action = RM_NOMATCH
|
||||
end
|
||||
|
||||
function on_match_and_change (prefix, attrs)
|
||||
action = RM_MATCH_AND_CHANGE
|
||||
log.info("Match and change")
|
||||
attrs["metric"] = attrs["metric"] + 7
|
||||
end
|
||||
|
||||
special_routes = {
|
||||
["172.16.10.4/24"] = on_match,
|
||||
["172.16.13.1/8"] = on_nomatch,
|
||||
["192.168.0.24/8"] = on_match_and_change,
|
||||
}
|
||||
|
||||
|
||||
if special_routes[prefix.network] then
|
||||
special_routes[prefix.network](prefix, attributes)
|
||||
elseif peer.stats.update_in % 3 == 0 then
|
||||
on_match(prefix, attributes)
|
||||
elseif peer.stats.update_in % 2 == 0 then
|
||||
on_nomatch(prefix, attributes)
|
||||
else
|
||||
on_match_and_change(prefix, attributes)
|
||||
end
|
||||
-- route_match returns table with following keys:
|
||||
-- integer action, required
|
||||
-- resultant status code. Should be one of RM_*
|
||||
-- table attributes, optional
|
||||
-- updated route attributes
|
||||
--
|
||||
|
||||
function route_match(prefix, attributes, peer,
|
||||
RM_FAILURE, RM_NOMATCH, RM_MATCH, RM_MATCH_AND_CHANGE)
|
||||
|
||||
log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string)
|
||||
|
||||
function on_match (prefix, attributes)
|
||||
log.info("Match")
|
||||
return {
|
||||
attributes = RM_MATCH
|
||||
}
|
||||
end
|
||||
|
||||
function on_nomatch (prefix, attributes)
|
||||
log.info("No match")
|
||||
return {
|
||||
action = RM_NOMATCH
|
||||
}
|
||||
end
|
||||
|
||||
function on_match_and_change (prefix, attributes)
|
||||
log.info("Match and change")
|
||||
attributes["metric"] = attributes["metric"] + 7
|
||||
return {
|
||||
action = RM_MATCH_AND_CHANGE,
|
||||
attributes = attributes
|
||||
}
|
||||
end
|
||||
|
||||
special_routes = {
|
||||
["172.16.10.4/24"] = on_match,
|
||||
["172.16.13.1/8"] = on_nomatch,
|
||||
["192.168.0.24/8"] = on_match_and_change,
|
||||
}
|
||||
|
||||
|
||||
if special_routes[prefix.network] then
|
||||
return special_routes[prefix.network](prefix, attributes)
|
||||
elseif peer.stats.update_in % 3 == 0 then
|
||||
return on_match(prefix, attributes)
|
||||
elseif peer.stats.update_in % 2 == 0 then
|
||||
return on_nomatch(prefix, attributes)
|
||||
else
|
||||
return on_match_and_change(prefix, attributes)
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user