Before using the instructions in this chapter, you must perform the procedures described in Write and Compile the ODL File.
The chapter has the following sections:
Makefile
file for linking with the following libraries:
libjuniper
libjunoscript
libui_odl.a
libmodule_odl.a
(generated by compiling the module’s ODL file as described in Invoke the ODL Makefile)
Makefile
file to files that are required for emitting JUNOScript tags:
Add the following statement to your module’s C program to reference the junoscript/xmlrpc.h
include file, which defines the JUNOScript macros and prototype functions used to produce JUNOScript-tagged output.
#include <junoscript/xmlrpc.h>
Add a statement for the module_odl.h
file, which was generated during compilation of the ODL file. It contains your module’s tag definitions. For example:
include <odl/module_odl.h>
xml_set_send_method()
function in your module’s initialization code. If you do not invoke this function, the JUNOScript library writes the module’s JUNOScript output to stdout. Depending on the destination for your module’s output, register one of the indicated functions:
ms_peer_send_line()
—If your module directs its output to the JUNOS management daemon (mgd), register the ms_peer_send_line()
function as indicated in the following function call. This implies that your module uses the mgmt_sock
package to communicate with mgd. The function also declares (casts) the ms_peer_send_line()
function’s type as xml_send_method_t
.
xml_set_send_method ((xml_send_method_t) ms_peer_send_line);
your_destination_definition_routine
—If your module does not use the mgmt_sock
package but also does not write to stdout, register the routine you have written for formatting and directing your module’s output. Its type must be xml_send_method_t
, as for the ms_peer_send_line()
function. Use a function call of the following form:
xml_set_send_method ((xml_send_method_t) your_destination_definition_routine);
In the file that contains your_destination_definition_routine
, use the following statement to declare the routine’s type. The void *
parameter is an opaque used by your routine to identify the destination for its JUNOScript output. The const char *
parameter is a printf
-style format string, and the remaining parameters are an ordered list of the format string’s arguments, one for each symbol (such as %s
) in the string. Your routine must use a function—either vsnprintf()
or a function you write with the same functionality—to format the second parameter and its arguments, then send them to the destination specified by the first (void *
) parameter.
typedef void (*xml_send_method_t)(void *, const char *, ...);
xml_set_vsnprintf_method()
function. If you do not call this function, JUNOScript uses the standard C library’s vsnprintf()
function. If your module uses a different formatting routine (as does the rpd module), use the following function to register it.
xml_set_vsnprintf_method((xml_vsnprintf_method_t) formatting_function);
junoscript/xmlrpc.h
file. The macros share the following common syntax. Note the final semicolon.
MACRO (destination, index, list of additional parameters);
MACRO | Specifies the kind of tag to emit; it is one of the following:
|
destination | A pointer to the data structure that records the state of your program’s connection with the destination to which it is sending JUNOScript tags. The value to use depends on the kind of program and destination:
|
index | Names the tag to emit, using the tag’s index as recorded in the module_odl.h file. By default, the ODL compiler derives the index from the tag name by making all letters in the tag name uppercase, replacing hyphens with underscores, and affixing the ODCI_ prefix. As an example, the index name for the <traffic-statistics> tag is ODCI_TRAFFIC_STATISTICS . You can use the define statement in the ODL file to specify an alternate index name, as described in Specify a Tag Index Name in Library Files. |
list of additional parameters | Specifies one or more additional parameters appropriate for the kind of tag you are defining. For a discussion of the acceptable values, see the following sections. |
XML_ELT
macro. The macro’s first two parameters are always the destination
and index
parameters discussed in Common Macro Syntax.
To include attributes on a simple tag, use the XML_OPEN
and XML_CLOSE
macros instead of XML_ELT
. For more information, see Emit a Container Tag or a Simple Tag with Attributes.
The XML_ELT
macro’s third parameter is a printf
-style statement that defines the tag’s contents. Usually, the statement includes one or more standard C symbols, such as %s
for a string, which represent the actual values that the module substitutes into the string when emitting the tag. The symbol type must match the type of the entity that the module substitutes for it, as specified in the module’s C file. Enclose the complete string in quotation marks ( " "
).
After the third parameter comes one additional parameter for each C symbol in the third parameter, identifying the construct in the module’s C program to substitute for the symbol.
As an example, the following macro emits the <input-bytes>
tag. The tag’s contents are the value of the variable ibytes
from the module’s C program file. The %qu
symbol indicates that the value is a 64-byte unsigned integer.
XML_ELT(peer, ODCI_INPUT_BYTES, "%qu", ptr->ibytes);
The module emits a tag like the following as a result:
<input-bytes>2014</input-bytes>
As another example, the following macro emits the <file>
tag. The tag’s content is a filename, which the module represents in its C file as three separate variables (path
, file
, and extension
).
XML_ELT(peer, ODCI_FILE, "%s/%s.%s", path, file, extension);
The module emits a tag like the following as a result:
<file>/var/tmp/snmpd.core</file>
printf
-style statement, such as the XML_ELT
macro’s third parameter.
As an example, the following code writes the result from the get_my_info()
function into a string called buffer
, which is then defined as the macro’s third parameter (the contents of the <my-info
> tag):
/* DO NOT USE */ char *buffer; buffer=get_my_info(); XML_ELT(peer, ODCI_MY_INFO, buffer);
The danger is that the buffer
string possibly contains percent (%
) signs or other characters that have special meaning in a printf
-style statement. The renderer’s attempt to interpret the characters as printf
symbols will probably fail, causing an error.
As shown in the following, the solution is to use the %s
symbol explicitly to define a parameter as a formatted string, and to define buffer
as the value to substitute for it.
char *buffer; buffer=get_my_info(); XML_ELT(peer, ODCI_MY_INFO, "%s", buffer);
XML_EMPTY
macro. The macro’s first two parameters are always the destination
and index
parameters discussed in Common Macro Syntax. Optionally, you can also define one or more attributes on an empty tag, as described in Assign Attributes to a Tag.The following example illustrates the macro for an empty tag without attributes.
XML_EMPTY(peer, ODCI_SNMP_TRAP_FLAG);
The module emits the following empty tag.
<snmp-trap-flag/>
XML_OPEN
and XML_CLOSE
macros, respectively. Each macro’s first two parameters are always the destination
and index
parameters discussed in Common Macro Syntax, and the values must match in the two macros. Optionally, the XML_OPEN
macro can have one or more attributes as described in Assign Attributes to a Tag.Also use these macros to emit a simple (noncontainer) tag element that has one or more attributes on its opening tag. The syntax is the same as for a container tag.
The following sample macro emits an opening and closing pair for a tag called <traffic-statistics>
which has no attributes. The ellipsis (...
) represents the tag pair’s contents, which are omitted here to make the structure of the pair more clear.
XML_OPEN(peer, ODCI_TRAFFIC_STATISTICS); ... XML_CLOSE(peer, ODCI_TRAFFIC_STATISTICS);
The module emits the following tags:
<traffic-statistics> ... </traffic-statistics>
If emitting a simple tag, define its contents by placing either an XML_DATA
or XML_OUT
macro between the XML_OPEN
and XML_CLOSE
macros. For examples, see Emit Tag Contents and Assign Attributes to a Tag.
For a container tag, define its child tags by placing sets of nested, paired XML_OPEN
and XML_CLOSE
macros between the outermost XML_OPEN
and XML_CLOSE
macros. Usually, the innermost child tags are simple (rather than container) tags, and so are defined by XML_ELT
macros (or by paired XML_OPEN
and XML_CLOSE
macros if the simple tags have attributes).
The following example is a more complete version of the macros for the <traffic-statistics>
container tag, which is the child of the <rpc-reply>
tag and contains two simple tags, <input-bytes>
and <output-bytes>
.
XML_OPEN(peer, ODCI_RPC_REPLY); XML_OPEN(peer, ODCI_TRAFFIC_STATISTICS); XML_ELT(peer, ODCI_INPUT_BYTES, "%u", input-bytes; XML_ELT(peer, ODCI_OUTPUT_BYTES, "%u", output-bytes); XML_CLOSE(peer, ODCI_TRAFFIC_STATISTICS); XML_CLOSE(peer, ODCI_RPC_REPLY);
The module emits a tag stream like the following:
<rpc-reply> <traffic-statistics> <input-bytes>42561</input-bytes> <output-bytes>34692</output-bytes> </traffic-statistics> </rpc-reply>
XML_OUT
or XML_DATA
macro. Each macro’s first two parameters are always the destination
and index
parameters discussed in Common Macro Syntax. Both, then, use additional parameters to define the tag’s contents. The distinction between the two macros is as follows:
XML_OUT
macro emits what is understood to be a single preformatted character string. The macro, therefore, accepts only one additional parameter (its third), which names the variable containing the string. For example, the following example defines the contents of the <interface-status>
tag to be the value of the status
variable:
XML_OUT(peer, ODCI_INTERFACE_STATUS, status);
The module emits a tag such as the following:
<interface-status>Disabled</interface-status>
XML_OUT
is identical to XML_ELT
.
XML_OPEN
and XML_CLOSE
macro pair to emit a simple tag, the XML_DATA
macro emits tag contents that can incorporate one or more values of any type. Its third parameter is a printf
-style statement that defines the format of the tag’s contents, and the remaining parameters provide values for the symbols in the printf
-style statement.
As an example, the following statement defines the <file>
tag’s contents as a pathname that is stored in the module’s C file in three separate variables—path
, file
, and extension:
XML_OPEN(peer, ODCI_FILE); XML_DATA(peer, "%s/%s.%s", path, file, extension) XML_CLOSE(peer, ODCI_FILE);
The module emits a tag like the following as a result:
<file>/var/tmp/snmpd.core</file>
XML_OPEN
and XML_CLOSE
macros for a simple tag instead of XML_ELT
or XML_OUT
is to include attributes on the tag. For examples of that usage, see Assign Attributes to a Tag.XML_EMPTY
or XML_OPEN
macro. The appropriate way to reference the attribute differs for user-defined and predefined attributes, as detailed in the following sections:
XML_EMPTY
or XML_OPEN
tag, use the XML_ATTR
macro. It has the following syntax:
char *XML_ATTR(attr_index , "%s", "attribute_value")
attr_index | Names the attribute to emit, identifying it by the index recorded in the modulee_odl.h file. Recall that the ODL compiler derives the index name by adding the suffix. _ATTR_ATTRIBUTE_NAME to the tag’s index name. It derives the ATTRIBUTE_NAME part by converting the name in the ODL attribute statement to all uppercase letters and replacing any hyphens with underscores. For more information, see Assign XML Attributes to a Tag.
As an example, the value for the attribute called |
%s | Ensures that the subsequent attribute_value is formatted properly. |
attribute_value
| Specifies the actual value to emit for the attribute. Enclose the value in quotation marks (" " ).
The following defines the value
XML_OPEN(peer, ODCI_TRAFFIC_STATISTICS, "%s", XML_ATTR(ODCI_TRAFFIC_STATISTICS_ATTR_HEADING, "%s", "Traffic Statistics")); The module emits the following tag as a result:
<traffic-statistics heading="Traffic Statistics"> |
XML_OPEN
or XML_EMPTY
macro’s list of parameters. The following sections explain how to emit predefined attributes:
junos:celsius
attribute expresses a temperature in degrees Celsius, as discussed in Express a Temperate in Degrees Celsius. The prototype function for including the attribute on an XML_OPEN
or XML_EMPTY
tag has the following format.
char *xml_attr_celcius (int degrees)
The degrees
argument is usually the name of a variable in the module’s C program file that stores the value to emit as the attribute’s value. The following example sets the junos:celcius
attribute on the <temperature>
tag to the value of the temp_cel
variable. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(peer, ODCI_TEMPERATURE, "%s", xml_attr_celcius(temp_cel));
When the XML_OPEN
macro is combined with XML_DATA
and XML_CLOSE
macros, the module emits the following tag as a result:
<temperature junos:celcius="29">29 degrees C / 84 degrees F</temperature>
junos:emit
attribute is encountered in a field where the emit
flag is specified, a newline
attribute is emitted. The prototype function for including the attribute on an XML_OPEN
tag has the following format:
char *xml_attr_emit (void)
In the following example, the junos:emit
attribute is used on the remote MEP count to prevent the CLI rendering from merging with other output. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(null, ODCI_CFM_REMOTE_MEP_COUNT, "%s", xml_attr_emit())
When the XML_OPEN
macro is combined with XML_DATA
and XML_CLOSE
macros, the module emits the following tag as a result:
<cfm-remote-mep-count junos:emit="emit">
junos:format
attribute defines a value for the renderer to display that is unrelated to the tag name or contents, as discussed in Display Alternate Text in a Field. The prototype function for including the attribute on an XML_OPEN
or XML_EMPTY
tag has the following format:
char *xml_attr_format (const char *format)
The format
argument is the character string for the renderer to display. The following example defines Enabled
as the string for the renderer to display as the value of the junos:format
attribute on the <administrative-status>
tag. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(peer, ODCI_ADMINISTRATIVE_STATUS, "%s", xml_attr_format("Enabled"));
When the XML_OPEN
macro is combined with XML_DATA
and XML_CLOSE
macros, the module emits the following tag as a result:
<administrative-status junos:format="Enabled">up</administrative-status>
junos:seconds
attribute expresses a time as a number of seconds, as discussed in Express a Time as a Number of Seconds. The prototype function for including the attribute on an XML_OPEN
or XML_EMPTY
tag has the following format:
char *xml_attr_seconds (time_t seconds)
The seconds
argument is usually the name of a variable in the module’s C program file that stores the value to emit as the value of the attribute. The following example sets the junos:seconds
attribute on the <uptime>
tag to the value of the up_secs
variable. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(peer, ODCI_UPTIME, "%s", xml_attr_seconds(up_secs));
When the XML_OPEN
macro is combined with XML_DATA
and XML_CLOSE
macros, the module emits the following tag as a result:
<uptime junos:seconds="180">3 minutes</uptime>
junos:style
attribute specifies which of several formats to use for a tag set, as discussed in Define Multiple Formats for the Same Tags. The prototype function for including the attribute on an XML_OPEN
tag has the following format:
char *xml_attr_style (const char *style)
The style
argument is the name of the #define
statement that the ODL compiler derives from the style
statement in the ODL file and records in the module_odl.h
file when the odc
command line includes the –u
option. The compiler bases the #define
statement’s name on the name of the tag with which the style is associated, converting all letters in the tag name to uppercase and any hyphens to underscores. It attaches the suffix STYLE_STYLE
, where STYLE is
the name assigned in the style
statement, also converted to all uppercase letters. For more information, see Define Multiple Formats for the Same Tags.
The following example sets the junos:style
attribute on the <fpc-information>
tag to the value represented by the index FPC_INFORMATION_STYLE_BRIEF
. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(peer, ODCI_FPC_INFORMATION, "%s", xml_attr_style (FPC_INFORMATION_STYLE_BRIEF));
The module emits the following opening tag as a result:
<fpc-information junos:style="brief">
xmlns
attribute defines the XML namespace to which a tag belongs. The prototype function for including the attribute on an XML_OPEN
tag has the following format.
char *xml_attr_xmlns (const char *namespace)
The namespace
argument is usually the string XML_NS
, which refers to the #define
statement of that name in the module_odl.h
file, as discussed in About the Namespace Attribute. The following example sets the xmlns
attribute on the <interface-information>
tag to the conventional value. Specifying a printf
-style statement as the third parameter guarantees that the attribute is formatted properly.
XML_OPEN(peer, ODCI_INTERFACE_INFORMATION, "%s", xml_attr_xmlns(XML_NS));
The <interface-information>
tag is defined in the junos-interface.dtd
file, so for JUNOS Release 5.4 the module emits the following tag as a result:
<interface-information xmlns="http://xml.juniper.net/junos/5.4R1/junos-interface">
<interface-information>
tag:
XML_OPEN(peer, ODCI_INTERFACE_INFORMATION, "%s %s", xml_attr_style(INTERFACE_INFORMATION_STYLE_BRIEF), xmlns(XML_NS));
The module emits the following opening tag as a result:
<interface-information junos:style="brief" xmlns="http://xml.juniper.net/junos/5.4R1/junos-interface">
The following defines the values of two user-defined attributes, heading
and size
, on the <ospf-database>
tag:
XML_OPEN(peer, ODCI_OSPF_DATABASE, "%s %s", XML_ATTR(ODCI_OSPF_DATABASE_ATTR_HEADING, "%s", "OSPF link state database"), XML_ATTR(ODCI_OSPF_DATABASE_ATTR_SIZE, "%s", "15000"));
The module emits the following opening tag as a result:
<ospf-database heading="OSPF link state database" size="15000">
The following example combines a JUNOScript attribute, junos:style
, and a user-defined attribute, header
, on the opening <chassis-information>
tag:
XML_OPEN(peer, ODCI_CHASSIS_INFORMATION, "%s %s", xml_attr_style(CHASSIS_INFORMATION_STYLE_DETAILED), XML_ATTR(ODCI_CHASSIS_INFORMATION_ATTR_HEADER, "%s", "Chassis information"));
The module emits the following opening tag as a result:
<interface-information junos:style="detailed" header="Chassis information">