Open Ethernet Networking (OpEN) API Guide and Reference Manual
3.6.0.3
|
While the native programming language of the OpEN API is C, it can be convenient (if not required) to develop your OpEN applications in a scripting language such a Python or Ruby. Scripting languages provide well-known advantages over C:
RPMs for Ruby and Python are available as RPM packages allowing these interpreters to be installed on the switch. Details on installing RPMs is provided in the ADK documentation. These packages provide the switch with required runtime libs as well as interactive environments you can use to experiment with (e.g., irb for Ruby, and cpython interpreter for python).
Language bindings for Ruby and Python are pre-installed on the switch. The following sections only apply to languages other than Ruby and Python, or to the case when the OpEN API has been modified and new Ruby/Python bindings need to be created.
If you are using Ruby/Python and have not modified the OpEN API then you need not read any further since language bindings have already been created for you are pre-installed on the switch.
In order to create bindings to scripting languages, we utilize a tool called SWIG. http://www.swig.org/ and http://en.wikipedia.org/wiki/SWIG provide more information on SWIG. Here, we discuss how SWIG is used by the ADK.
In the ADK, there is a directory named swig. This directory in turn contains one directory for each supported language binding. For example, the python directory contains files and a Makefile that can be used to generate a SWIG module that will provide bindings for python.
In the examples directory, you may find example applications written not only in C, but ported to one or more of the scripting languages supported via SWIG. For example, in the directory examples/vlan, one will find Ruby and Python sources that implement the same logic as is implemented by the C example also found there. You can use these example for creating your own script-based OpEN applications.
The steps required to create bindings are as follows:
Install swig on your development host. We've successfully built bindings with versions 1.3.40 and 2.0.9. If using a different version, we highly recommend installing a stable, not a development version. Install using yum:
$ sudo yum install swig
SWIG documentation might direct you to install developer packages for the language being targeted (e.g., the python dev package). In the case of Ruby and Python, we have provided the headers for the supported versions of Ruby and Python in the ADK, so that you need not worry about installing the dev packages. If you have dev packages installed, they will be ignored (the Makefile is hardcoded to point to the headers we provide, which are designed to match the versions of Python and Ruby supplied as switch RPMs).
For Python, we support python 2.6.6. The build requires header files from the Python 2.6.6 dev package, and these are located in the ADK in the python/python2.6.6 directory. The Makefile points to these headers via the PYTHON_H export.
For Ruby, we support Ruby 1.8.7. The build requires header files from the Ruby 1.8.7 dev package, and these are located in the ADK in the ruby/ruby1.8.7 directory. The Makefile points to these headers via the RUBY_H export.
When you type make, a few things happen.
Note: you may have to update the Makefile to specify the location of header files for the language you are building a binding for. The default makefiles should be properly set for the languages we explicitly support.
OpEN applications (as you can see from the C source files in the example directory) share common code to initialize a connection to the switch, get version information, and so forth. In addition, depending on the state of the ADK or the targeted scripting language, there may need to be helper code written in the target language itself. The OpENUtil module encapsulates this code in a set of classes that can be used by your scripting applications. There is one OpENUtil module per language. For example, the python OpENUtil module is named OpENUtil.py, and is located in the swig/python directory.
Sample code from the examples directory depends on this module. You are free to use these modules in your code, or create a similar module of your own (or just copy and paste the code into your sources if you like). We came up with the OpENUtil module to eliminate code duplication and ease the maintenance of our example code.
The following sections provide some details for each language we support.
Note: Python language bindings are pre-installed on the switch. This section need only be used if the OpEN API has been modified.
We support Python 2.6.6. Later versions may work, but are not supported. Regardless, you should ensure that the developer package installed on the development host matches the version of the python RPM installed on the switch.
The RPM documentation details how to install the python RPM on the switch.
To install the developer package on CentOS 6.2:
$ sudo yum install python-devel
To build the bindings:
$ cd swig/python $ make
The build should generate two files:
_OpEN.so OpEN_py.py
A third file:
OpENUtil.py
is also located in the same directory, but was not generated by the build.
Copy _OpEN.so, OpEN_py.py, and OpENUtil.py to the switch (e.g., into /mnt/fastpath).
To run your python application, copy it to the same directory as the above files, and then type:
> enable # linuxsh # # python app.py
Note: Ruby language bindings are pre-installed on the switch. This section need only be used if the OpEN API has been modified.
We support Ruby 1.8.7. Later versions may work, but are not supported. Regardless, you should ensure that the developer package installed on the development host matches the version of the ruby RPM installed on the switch.
The RPM documentation details how to install the ruby RPM on the switch.
To install the developer package on CentOS 6.2:
$ sudo yum install ruby-devel
To build the bindings:
$ cd swig/ruby $ make
The build should generate two files:
OpEN.so
A second file:
OpENUtil.rb
is also located in the same directory, but was not generated by the build.
Copy OpEN.so and OpENUtil.rb to the switch. It is suggested that you copy these files to /mnt/fastpath/usr/lib/ruby/1.8 where they are accessible by default with any special load paths.
To run your ruby application, copy it to the switch and then type:
> enable # linuxsh # # ruby app.rb
SWIG supports the generation of bindings for almost 2 dozen languages, the full list can be found at http://www.swig.org/compare.html. While we expect python and ruby bindings to cover most use cases, it might be that case that you need bindings for one of the other languages SWIG supports.
One of the reasons we decided to distribute the infrastructure for building the python and ruby bindings was a hope that others might be able to use our scripts and Makefiles as a starting point for wrapping other languages.
Documentation for using swig can be found at http://www.swig.org, but here are some areas that you need to know about.
In OpENUtil, you will find a class named OpENEvent. This class emulates a macro in the OpEN ADK. You will need to port this class to your target language if you code uses this type.
In addition to emulating the macro, a typemap was created to support a non-POD type that is used by these macros. Here is the example from Ruby, which is found in ruby/genifile.sh:
echo "%typemap(in) unsigned char[((OPEN_EVENT_LAST) / 8) + 1] (unsigned char tmp[((OPEN_EVENT_LAST) / 8) + 1]) {" echo "\$1 = &tmp[0];" echo "memset((void *) \$1, 0, ((OPEN_EVENT_LAST) / 8) + 1);" echo "memcpy((void *) \$1, (void *) RSTRING(\$input)->ptr, RSTRING(\$input)->len);" echo "}"
Most of this typemap is portable with exception to the calls to RSTRING, which are Ruby specific. If you inspect the same typemap in the python version of genifile.sh, you will see these are replaced with calls to the python runtime. SWIG documentation on typemaps plus the above examples should get you through porting this typemap.
We may in the future eliminate the use of macros and modify the OpEN ADK so that this typemap, and the macro emulation code is no longer necessary. Check with your support person for details.
The following code:
echo "%pointer_functions(uint32_t, uint32_tp);"
in the genifile script supports functions in the ADK that require a pointer to uint32_t as an argument.
Usage in script (Python example here) shows how to allocate a pointer, pass it to a function, and extract the returned value:
vlan_num_p = OpEN.new_uint32_tp() ret = OpEN.openapiVlanNextGet(self.m_client, vlan_num, vlan_num_p) if ret == OpEN.OPEN_E_NONE: vlan_num = OpEN.uint32_tp_value(vlan_num_p)
At the time of this writing, several of the functions in the ADK are specified as #defines in an ADK file called rcp/rpcclt_openapi_map.h. For example:
#define openapiBoxsNumOfFansGet rpcclt_openapiBoxsNumOfFansGet
This presents a problem for SWIG, which does not recognize the need to provide wrappings for these functions.
Most of the processing we do outside of creating the ".i" file concerns itself with patching the generated swig wrapper with code that registers these names in a way that will cause swig to generate bindings.
The difficulty with this is that SWIG's ruby code and python code differ in how this is done; for ruby, the name information is represented by function calls to register the name, while in python, this is done at compile time with table entries.
By inspection of the generated swig wrapper code to see how function names are being registered (odds are it will be similar to either the Ruby or Python approaches), you should be able to modify our Makefile and build scripts to patch the swig wrapper code appropriately. The artifacts used in the process (temporary files) are left in the build directory; inspection of them should help clarify what is happening.
If you run into difficulty with this, contact your Broadcom support person for help.
We are looking into making the ADK code more wrappable, by eliminating these #defines.