Cint: the C interpreter
Cint is a C interpreter built into the SDK. It runs C-like programs inside
syncd and lets them call the SDK API (the bcm_* functions) directly,
with real structures, enums and constants. Use it for API features that have
no diag-shell command, to read state in the SDK’s own terms, or to repeat a
sequence of calls from a script. Start it with cint.
This chapter covers running Cint and the interpreter itself; The Cint language describes the C subset it accepts, and Cint recipes has ready-made read-only programs for Trident 3.
Warning
A Cint program runs inside syncd with full access to the SDK. A call
that changes state (*_set, *_add, *_create, *_destroy,
*_delete…) changes the hardware behind the SAI’s back: SONiC does not
know about the change, will not undo it, and may later fail or overwrite
it. A wrong argument, such as a bad pointer or an array that is too small,
can crash syncd; SONiC then restarts syncd and swss and traffic
stops while the switch is reprogrammed. There is no way to interrupt a
running program: a loop that never ends keeps the shell busy until
syncd is restarted. On a production switch, run only read-only
programs that you have read and understood.
When to use Cint
Diag commands first. For displaying state, the diag commands (
l3 defip show,l2 show,ps, …) are quicker to use and harder to get wrong. Prefer them when they show what you need.Cint when no command shows it, when you want the API’s view of an object (the values SAI passed to the SDK, before they are encoded into table entries), or when you need to loop, filter or combine values. Cint can also run diag commands itself; see Running diag commands from Cint.
Raw tables with
dump,getregorlistmemwhen you need the hardware encoding rather than the API view.
Starting and leaving the interpreter
cint with no argument prints Entering C Interpreter. Type 'exit;' to
quit. and starts an interactive session at the cint> prompt.
Statements end with ; and are run as soon as they are complete; a
function definition or a { … } block may span several lines. exit; or
quit; returns to drivshell>.
Unvalidated
drivshell>cint
cint> print bcm_info_t;
cint> exit;
Interactive mode needs a terminal, so use it through bcmsh.
Through bcmcmd the shell stays at cint> and bcmcmd waits until
its timeout; use a file instead.
Running a file
cint <file> [<arg> …] reads and runs a file, then returns to
drivshell>. The file is opened by syncd, so the path is a path
inside the syncd container. Copy the file to /root there with
docker cp (as root), and use an absolute path:
Hardware-validated
$ sudo docker cp port_status.c syncd:/root/
$ bcmcmd -t 120 "cint /root/port_status.c"
Do not copy into /tmp or /var/tmp: inside the syncd container
both are separate in-memory file systems, and docker cp writes
underneath them, where syncd cannot see the file. docker cp still
exits 0, and cint then reports error: could not open file.
A file is read and run one top-level statement at a time, as it is parsed. This has three consequences:
Statements before an error have already run when the error is reported.
After a syntax error, the rest of the file is still read and checked but nothing more is run. Every later line is skipped, including any cleanup code at the end of the file.
A run-time error (an undeclared name, a wrong argument type, a failed
printfconversion) abandons the top-level statement it occurs in. If that statement is a function call, the rest of the function, and of every function that called it, is skipped. The file continues with the next top-level statement.
exit; in a file stops reading it at that point.
cint always returns success to the shell, even when the program failed
or the file could not be opened, and bcmcmd exits 0. Make your
program print a final line such as DONE and check for it, and read the
whole output for error lines.
bcmcmd waits 30 seconds for the prompt by default. Programs that
walk large tables (the L2 or route table) can take longer; give a larger
-t. If bcmcmd times out, the program keeps running inside syncd.
Arguments
Words after the file name are passed to the program in two global
variables: ARGC (an int) and ARGV (an array of strings),
starting with the first word after the file name. At most 16 arguments are
allowed. There is no atoi in Cint; convert numbers yourself (the
Cint recipes show a small helper).
if (ARGC > 0) {
printf("first argument: %s\n", ARGV[0]);
}
Line numbers in error messages
Syntax errors always show the offending line and its number. Run-time errors
are printed as ** error: <message> without a location. To get the file and
line in run-time errors too, put allow_file_info before the file name:
Unvalidated
drivshell> cint allow_file_info /root/port_status.c
The word allow_file_info is then also passed to the program as
ARGV[0], so the program’s own arguments start at ARGV[1].
#include
A file can include another with #include "/path/file.c". A relative name
is looked up from syncd’s working directory and then in the directories
of the CINT_INCLUDE_PATH environment variable of syncd; use absolute
paths. Includes may nest 64 deep. #include is the only preprocessor
directive; see The Cint language.
The interpreter keeps its state
The interpreter lives as long as syncd. Global variables and functions
defined by one cint run are still there in the next run, and in the next
interactive session. Two consequences:
Running a file twice fails on the second run with
identifier '<name>' redeclaredfor every global variable it declares. Defining a function again is allowed and replaces the old definition.A name defined by an earlier program can hide a mistake in a new one.
Start files with cint_reset();, as Broadcom’s own examples do
(OpenBCM sdk-6.5.27 CINT interpreter sources (src/appl/cint, src/appl/diag/cint) and Trident 3 CINT examples with logs (src/examples/xgs/TD3)). It discards everything defined so far and
reloads the SDK’s functions and types. It affects only the interpreter, not
the switch.
What the interpreter knows
Cint can only call functions and use types that were registered with it when the SDK was built. On this build that is:
the SDK API: 10,521
bcm_*functions (1,445 of them SDK macros such asBCM_GPORT_LOCAL_SET, registered as functions), 1,385 structures, 1,180 enums, 212 typedefs, 304 callback types and 11,916 constants;a few
soc_*functions (soc_mem_read,soc_property_get…),diag_*register and memory helpers,sal_*utilities (sal_memset,sal_strcmp,sal_sleep…) andCOMPILER_64_*helpers for 64-bit values;PHY and port-macro APIs (
phymod_*,portmod_*);logical-table (
bcmlt_*) and embedded-core (edki_*) functions, which belong to newer switch families and may not work on Trident 3;the interpreter’s built-ins, listed below.
In total that is 11,457 functions, 1,585 structures, 1,294 enums, 331 callback types and 12,482 constants. Cint API on this build lists all of them with prototypes, and lists separately everything that is not in the public OpenBCM 6.5.27 release.
A function that exists in the library but is not registered cannot be
called, and an extern declaration does not change that: for example
soc_mem_search is not available. Some registered functions are
unusable because a type they need is missing; soc_reg_get fails because
soc_reg_t is not a known type. Check a name with cint_defined("name")
(1 if known) or list names with cint list.
Interpreter commands
Statements starting with the word cint are commands to the interpreter
itself. Arguments are bare words, not quoted strings.
cint list [<kind> …] [<substring>];List registered names containing
<substring>, with their kind.<kind>restricts the list tofunction,struct,enum,constant,atomic,fp(callback types),macrooriterator. Without a substring the list is very long. Example:cint list function bcm_port_info;.cint var <name>;Show a variable’s type, address and size.
cint typecheck;Check every registered type for consistency.
cint load (loading a shared library) and cint yapi are not included
in this build and print an error.
To see the layout of a structure or the values of an enum, print the type
name:
Unvalidated
cint> print bcm_port_info_t;
cint> print bcm_stat_val_t;
cint> cint list function bcm_port_info;
Looking up a function
Cint tells you whether a name exists and how a type is laid out, but not what a function does. Combine it with these references:
- On the switch
cint list function <part of name>;finds functions,print <type>;shows a structure’s members and size or an enum’s values as this build has them, andcint_defined("name")checks a single name. When a public header and the switch disagree about a structure, the switch is right: its SDK is newer than any public release.- This guide
Cint API on this build has the prototype of every registered function, grouped by module, and separate lists of the functions, structures, enums and values, callback types and constants that are not in public OpenBCM. For those there is no public documentation; the prototype and layout are what you have to go on. Cint recipes has complete read-only programs for this switch.
- OpenBCM headers
The public SDK API headers, one per module (
l3.hforbcm_l3_*,port.hforbcm_port_*,field.hforbcm_field_*…), declare each function with its structures, flags and short comments. They are the closest thing to an API reference (OpenBCM sdk-6.5.27 SDK API headers (include/bcm/*.h) and the Cint registration data generated from them (bcm_cint_data.c)).- OpenBCM example programs
Broadcom’s Cint examples for each XGS family, including a Trident 3 set with a summary table and console logs, show complete call sequences for VLANs, L3, MPLS, VXLAN, field processor and more (OpenBCM sdk-6.5.27 CINT interpreter sources (src/appl/cint, src/appl/diag/cint) and Trident 3 CINT examples with logs (src/examples/xgs/TD3)). They are written for a bare SDK (
BCM.0>) and set up the switch from scratch; read them for the call order, do not run them on a SONiC switch.- OpenNSL documentation
OpenNSL is a subset of the SDK API with the
opennsl_prefix instead ofbcm_(opennsl_l3_route_addforbcm_l3_route_add). Its API reference and overview pages for L2, L3, ports, COS, KNET, statistics and trunks explain parameters and flags that carry over to thebcm_*functions (OpenNSL 3.x documentation (doc/html) and sal/driver.h (opennsl_driver_shell)).- Open-source network operating systems
FBOSS drives the
bcm_*API on Trident and Tomahawk switches; its Broadcom agent shows production call sequences for egress objects, ECMP, routes, ports and ACLs (FBOSS Broadcom agent (fboss/agent/hw/bcm): C++ code driving the bcm_* SDK API). Stratum wraps about 150bcm_*functions in a single file (Stratum BcmSdkWrapper (stratum/hal/lib/bcm/sdk/bcm_sdk_wrapper.cc): bcm_* SDK API calls).- SDK release notes
Broadcom’s per-release spreadsheets of resolved issues and improvements name the
bcm_*functions and structures each fix concerns (SDK-6.5.20..6.5.27 Resolved-Issues-Improvements.xlsx (7 files)).
Broadcom’s SAI library, which makes the bcm_* calls on a SONiC switch,
is not open source, so there is no public code showing which calls SONiC
makes for a given SAI object. FBOSS and Stratum are the closest public
equivalent.
Built-in functions
Function |
Purpose |
|---|---|
|
Formatted output; see The Cint language. |
|
Forget all variables and functions defined so far. |
|
1 if |
|
Print all variables. |
|
Run a diag-shell command line; see below. |
|
Run an rc script (see Scripting). |
|
Text for an SDK return code, e.g. |
|
Delays and time. |
|
Timing. |
|
Replacements for the C library, which is not available. |
Constants TRUE, FALSE and NULL are predefined.
Running diag commands from Cint
bshell(unit, "command line") runs a diag-shell command line, as if typed
at the prompt, and returns its result: 0 for success, a negative value for
failure (−3 for an unknown command, which also prints Unknown command:
<word>). Its output goes to the same place as the program’s. It is useful
for showing state between API calls, as Broadcom’s examples do with l3
egress show or vlan show. The same safety rules apply as at the prompt.
BCMSAI Cint
The SAI’s own BCMSAI Cint is not included in this build; it only
prints a message. Use cint.
Troubleshooting
Message |
Meaning |
|---|---|
|
The path does not exist inside the |
|
The line is not valid Cint. Common causes: a C cast such as
|
|
The name is not defined, or the function is not registered with Cint
(check with |
|
The variable exists from an earlier run. Add |
|
The type is not registered in this build. |
|
Pass a variable of the declared type; remember |
|
Check the prototype with |
|
|
|
A |
|
Checked by Cint before the access; fix the program. |
A negative number from an SDK call |
An SDK return code ( |
No output at all and |
The program is still running or the shell is at |