diff --git a/Makefile.am b/Makefile.am index e96ed132752b..33cd843839cb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = meta lib vslib python +SUBDIRS = meta lib vslib python pyext if SYNCD SUBDIRS += syncd saiplayer saidump saidiscovery saisdkdump saiasiccmp tests diff --git a/configure.ac b/configure.ac index 8a5c5c4fdde7..f3c85cd063c6 100644 --- a/configure.ac +++ b/configure.ac @@ -10,6 +10,8 @@ AC_PROG_CC AC_PROG_CXX AC_PROG_LIBTOOL AC_HEADER_STDC +AM_PATH_PYTHON +AM_PATH_PYTHON3 AM_CONDITIONAL(sonic_asic_platform_barefoot, test x$CONFIGURED_PLATFORM = xbarefoot) AM_CONDITIONAL(sonic_asic_platform_mellanox, test x$CONFIGURED_PLATFORM = xmellanox) @@ -76,6 +78,10 @@ AC_ARG_ENABLE(redis-test, esac],[rtest=false]) AM_CONDITIONAL(RTEST, test x$rtest = xtrue) +AM_CONDITIONAL(ARCH64, test `getconf LONG_BIT` = "64") + +AC_PATH_PROGS(SWIG, [swig3.0 swig]) + CFLAGS_COMMON="" CFLAGS_COMMON+=" -ansi" CFLAGS_COMMON+=" -fPIC" @@ -144,4 +150,7 @@ AC_OUTPUT(Makefile saidiscovery/Makefile saiasiccmp/Makefile tests/Makefile + pyext/Makefile + pyext/py2/Makefile + pyext/py3/Makefile python/setup.py) diff --git a/debian/control b/debian/control index a555e899efa8..044c2ee9e7b5 100644 --- a/debian/control +++ b/debian/control @@ -114,3 +114,16 @@ Depends: libsaimetadata (= ${binary:Version}), ${misc:Depends} Description: debugging symbols for libsaimetadata + +Package: python-pysairedis +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Pre-Depends} +Section: libs +Description: This package contains Switch State Service sairedis Python2 library. + +Package: python3-pysairedis +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Pre-Depends} +Section: libs +Description: This package contains Switch State Service sairedis Python3 library. + diff --git a/debian/python-pysairedis.dirs b/debian/python-pysairedis.dirs new file mode 100644 index 000000000000..96a2dca18f0c --- /dev/null +++ b/debian/python-pysairedis.dirs @@ -0,0 +1 @@ +usr/lib/python2.7 diff --git a/debian/python-pysairedis.install b/debian/python-pysairedis.install new file mode 100644 index 000000000000..3108ecb46f29 --- /dev/null +++ b/debian/python-pysairedis.install @@ -0,0 +1 @@ +usr/lib/python2.7/dist-packages/pysairedis/* diff --git a/debian/python3-pysairedis.dirs b/debian/python3-pysairedis.dirs new file mode 100644 index 000000000000..b06a39903d21 --- /dev/null +++ b/debian/python3-pysairedis.dirs @@ -0,0 +1 @@ +usr/lib/python3 diff --git a/debian/python3-pysairedis.install b/debian/python3-pysairedis.install new file mode 100644 index 000000000000..6b510bba9910 --- /dev/null +++ b/debian/python3-pysairedis.install @@ -0,0 +1 @@ +usr/lib/python3/dist-packages/pysairedis/* diff --git a/m4/python3.m4 b/m4/python3.m4 new file mode 100644 index 000000000000..e4ffd504015f --- /dev/null +++ b/m4/python3.m4 @@ -0,0 +1,195 @@ +## ------------------------ -*- Autoconf -*- +## Python 3 file handling, adapted from: +## Python file handling +## From Andrew Dalke +## Updated by James Henstridge +## ------------------------ +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PATH_PYTHON3([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# --------------------------------------------------------------------------- +# Adds support for distributing Python modules and packages. To +# install modules, copy them to $(pythondir), using the python_PYTHON +# automake variable. To install a package with the same name as the +# automake package, install to $(pkgpythondir), or use the +# pkgpython_PYTHON automake variable. +# +# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as +# locations to install python extension modules (shared libraries). +# Another macro is required to find the appropriate flags to compile +# extension modules. +# +# If your package is configured with a different prefix to python, +# users will have to add the install directory to the PYTHONPATH +# environment variable, or create a .pth file (see the python +# documentation for details). +# +# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will +# cause an error if the version of python installed on the system +# doesn't meet the requirement. MINIMUM-VERSION should consist of +# numbers and dots only. +AC_DEFUN([AM_PATH_PYTHON3], + [ + dnl Find a Python 3 interpreter + m4_define_default([_AM_PYTHON3_INTERPRETER_LIST], + [python3 python3.0 python3.1]) + + m4_if([$1],[],[ + dnl No version check is needed. + # Find any Python 3 interpreter. + if test -z "$PYTHON3"; then + AC_PATH_PROGS([PYTHON3], _AM_PYTHON3_INTERPRETER_LIST, :) + fi + am_display_PYTHON3=python3 + ], [ + dnl A version check is needed. + if test -n "$PYTHON3"; then + # If the user set $PYTHON3, use it and don't search something else. + AC_MSG_CHECKING([whether $PYTHON3 version >= $1]) + AM_PYTHON3_CHECK_VERSION([$PYTHON3], [$1], + [AC_MSG_RESULT(yes)], + [AC_MSG_ERROR(too old)]) + am_display_PYTHON3=$PYTHON3 + else + # Otherwise, try each interpreter until we find one that satisfies + # VERSION. + AC_CACHE_CHECK([for a Python3 interpreter with version >= $1], + [am_cv_pathless_PYTHON3],[ + for am_cv_pathless_PYTHON3 in _AM_PYTHON3_INTERPRETER_LIST none; do + test "$am_cv_pathless_PYTHON3" = none && break + AM_PYTHON3_CHECK_VERSION([$am_cv_pathless_PYTHON3], [$1], [break]) + done]) + # Set $PYTHON3 to the absolute path of $am_cv_pathless_PYTHON3. + if test "$am_cv_pathless_PYTHON3" = none; then + PYTHON3=: + else + AC_PATH_PROG([PYTHON3], [$am_cv_pathless_PYTHON3]) + fi + am_display_PYTHON3=$am_cv_pathless_PYTHON3 + fi + ]) + + if test "$PYTHON3" = :; then + dnl Run any user-specified action, or abort. + m4_default([$3], [AC_MSG_ERROR([no suitable Python3 interpreter found])]) + else + + dnl Query Python3 for its version number. Getting [:3] seems to be + dnl the best way to do this; it's what "site.py" does in the standard + dnl library. + + AC_CACHE_CHECK([for $am_display_PYTHON3 version], [am_cv_python3_version], + [am_cv_python3_version=`$PYTHON3 -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) + AC_SUBST([PYTHON3_VERSION], [$am_cv_python3_version]) + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of PYTHON3_PREFIX and PYTHON3_EXEC_PREFIX. These are made + dnl distinct variables so they can be overridden if need be. However, + dnl general consensus is that you shouldn't need this ability. + + AC_SUBST([PYTHON3_PREFIX], ['${prefix}']) + AC_SUBST([PYTHON3_EXEC_PREFIX], ['${exec_prefix}']) + + dnl At times (like when building shared libraries) you may want + dnl to know which OS platform Python3 thinks this is. + + AC_CACHE_CHECK([for $am_display_PYTHON3 platform], [am_cv_python3_platform], + [am_cv_python3_platform=`$PYTHON3 -c "import sys; sys.stdout.write(sys.platform)"`]) + AC_SUBST([PYTHON3_PLATFORM], [$am_cv_python3_platform]) + + AC_CACHE_CHECK([for $am_display_PYTHON3 bldlibrary], [am_cv_python3_bldlibrary], + [am_cv_python3_bldlibrary=`$PYTHON3 -c "import sys; import sysconfig; sys.stdout.write(sysconfig.get_config_var('BLDLIBRARY'))"`]) + AC_SUBST([PYTHON3_BLDLIBRARY], [$am_cv_python3_bldlibrary]) + + dnl Set up 4 directories: + + dnl python3dir -- where to install python3 scripts. This is the + dnl site-packages directory, not the python3 standard library + dnl directory like in previous automake betas. This behavior + dnl is more consistent with lispdir.m4 for example. + dnl Query distutils for this directory. distutils does not exist in + dnl Python3 1.5, so we fall back to the hardcoded directory if it + dnl doesn't work. + AC_CACHE_CHECK([for $am_display_PYTHON3 script directory], + [am_cv_python3_python3dir], + [if test "x$prefix" = xNONE + then + am_py_prefix=$ac_default_prefix + else + am_py_prefix=$prefix + fi + am_cv_python3_python3dir=`$PYTHON3 -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || + echo "$PYTHON3_PREFIX/lib/python$PYTHON3_VERSION/site-packages"` + case $am_cv_python3_python3dir in + $am_py_prefix*) + am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` + am_cv_python3_python3dir=`echo "$am_cv_python3_python3dir" | sed "s,^$am__strip_prefix,$PYTHON3_PREFIX,"` + ;; + esac + ]) + AC_SUBST([python3dir], [$am_cv_python3_python3dir]) + + dnl pkgpython3dir -- $PACKAGE directory under python3dir. Was + dnl PYTHON3_SITE_PACKAGE in previous betas, but this naming is + dnl more consistent with the rest of automake. + + AC_SUBST([pkgpython3dir], [\${python3dir}/$PACKAGE]) + + dnl pyexecdir -- directory for installing python3 extension modules + dnl (shared libraries) + dnl Query distutils for this directory. distutils does not exist in + dnl Python3 1.5, so we fall back to the hardcoded directory if it + dnl doesn't work. + AC_CACHE_CHECK([for $am_display_PYTHON3 extension module directory], + [am_cv_python3_pyexecdir], + [if test "x$exec_prefix" = xNONE + then + am_py_exec_prefix=$am_py_prefix + else + am_py_exec_prefix=$exec_prefix + fi + am_cv_python3_pyexecdir=`$PYTHON3 -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || + echo "$PYTHON3_EXEC_PREFIX/lib/python$PYTHON3_VERSION/site-packages"` + case $am_cv_python3_pyexecdir in + $am_py_exec_prefix*) + am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` + am_cv_python3_pyexecdir=`echo "$am_cv_python3_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON3_EXEC_PREFIX,"` + ;; + esac + ]) + AC_SUBST([py3execdir], [$am_cv_python3_pyexecdir]) + + dnl pkgpy3execdir -- $(py3execdir)/$(PACKAGE) + + AC_SUBST([pkgpy3execdir], [\${py3execdir}/$PACKAGE]) + + dnl Run any user-specified action. + $2 + fi + +]) + + +# AM_PYTHON3_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# --------------------------------------------------------------------------- +# Run ACTION-IF-TRUE if the Python3 interpreter PROG has version >= VERSION. +# Run ACTION-IF-FALSE otherwise. +# This test uses sys.hexversion instead of the string equivalent (first +# word of sys.version), in order to cope with versions such as 2.2c1. +# This supports Python3 2.0 or higher. (2.0 was released on October 16, 2000). +AC_DEFUN([AM_PYTHON3_CHECK_VERSION], + [prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python3 3.0 and a list in 2.x +minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] +minverhex = 0 +# xrange is not present in Python3yy 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] +sys.exit(sys.hexversion < minverhex)" + AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) diff --git a/meta/sai_serialize.h b/meta/sai_serialize.h index 82c332fbfa8f..c4caaf1c2e38 100644 --- a/meta/sai_serialize.h +++ b/meta/sai_serialize.h @@ -308,6 +308,18 @@ void sai_deserialize_object_meta_key( _In_ const std::string &s, _Out_ sai_object_meta_key_t& meta_key); +void sai_deserialize_ip_address( + _In_ const std::string& s, + _Out_ sai_ip_address_t& ipaddr); + +void sai_deserialize_ip_prefix( + _In_ const std::string &s, + _Out_ sai_ip_prefix_t &ip_prefix); + +void sai_deserialize_mac( + _In_ const std::string& s, + _Out_ sai_mac_t& mac); + // deserialize notifications void sai_deserialize_fdb_event_ntf( diff --git a/pyext/Makefile.am b/pyext/Makefile.am new file mode 100644 index 000000000000..ceeeba214391 --- /dev/null +++ b/pyext/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = py2 py3 + +ACLOCAL_AMFLAGS = -I m4 diff --git a/pyext/fdb.h b/pyext/fdb.h new file mode 100644 index 000000000000..0789b54ae105 --- /dev/null +++ b/pyext/fdb.h @@ -0,0 +1,57 @@ + +// TODO auto generate + +typedef struct _sai_fdb_api_t +{ + sai_status_t create_fdb_entry( + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_fdb_entry( + _In_ const sai_fdb_entry_t *fdb_entry); + + sai_status_t set_fdb_entry_attribute( + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ const sai_attribute_t *attr); + + sai_status_t get_fdb_entry_attribute( + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t flush_fdb_entries( + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t create_fdb_entries( + _In_ uint32_t object_count, + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t remove_fdb_entries( + _In_ uint32_t object_count, + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t set_fdb_entries_attribute( + _In_ uint32_t object_count, + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ const sai_attribute_t *attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t get_fdb_entries_attribute( + _In_ uint32_t object_count, + _In_ const sai_fdb_entry_t *fdb_entry, + _In_ const uint32_t *attr_count, + _Inout_ sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + +} sai_fdb_api_t; diff --git a/pyext/getapi.h b/pyext/getapi.h new file mode 100644 index 000000000000..c61e98419a3d --- /dev/null +++ b/pyext/getapi.h @@ -0,0 +1,10 @@ + +// need to be extern C + +sai_status_t sai_get_switch_api(sai_switch_api_t* out); +sai_status_t sai_get_lag_api(sai_lag_api_t* out); +sai_status_t sai_get_router_interface_api(sai_router_interface_api_t* out); +sai_status_t sai_get_next_hop_api(sai_next_hop_api_t* out); +sai_status_t sai_get_route_api(sai_route_api_t* out); +sai_status_t sai_get_vlan_api(sai_vlan_api_t* out); +sai_status_t sai_get_fdb_api(sai_fdb_api_t* out); diff --git a/pyext/lag.h b/pyext/lag.h new file mode 100644 index 000000000000..78dbd21e0d62 --- /dev/null +++ b/pyext/lag.h @@ -0,0 +1,57 @@ + +// TODO auto generate + +typedef struct _sai_lag_api_t +{ + sai_status_t create_lag( + _Out_ sai_object_id_t *lag_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_lag( + _In_ sai_object_id_t lag_id); + + sai_status_t set_lag_attribute( + _In_ sai_object_id_t lag_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_lag_attribute( + _In_ sai_object_id_t lag_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t create_lag_member( + _Out_ sai_object_id_t *lag_member_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_lag_member( + _In_ sai_object_id_t lag_member_id); + + sai_status_t set_lag_member_attribute( + _In_ sai_object_id_t lag_member_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_lag_member_attribute( + _In_ sai_object_id_t lag_member_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t create_lag_members( + _In_ sai_object_id_t switch_id, + _In_ uint32_t object_count, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_object_id_t *object_id, + _Out_ sai_status_t *object_statuses); + + sai_status_t remove_lag_members( + _In_ uint32_t object_count, + _In_ const sai_object_id_t *object_id, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + +} sai_lag_api_t; diff --git a/pyext/nexthop.h b/pyext/nexthop.h new file mode 100644 index 000000000000..244d8c23ba96 --- /dev/null +++ b/pyext/nexthop.h @@ -0,0 +1,25 @@ + +// TODO auto generate + +typedef struct _sai_next_hop_api_t +{ + sai_status_t create_next_hop( + _Out_ sai_object_id_t *next_hop_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_next_hop( + _In_ sai_object_id_t next_hop_id); + + sai_status_t set_next_hop_attribute( + _In_ sai_object_id_t next_hop_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_next_hop_attribute( + _In_ sai_object_id_t next_hop_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + +} sai_next_hop_api_t; + diff --git a/pyext/py2/Makefile.am b/pyext/py2/Makefile.am new file mode 100644 index 000000000000..c73c0e5421b2 --- /dev/null +++ b/pyext/py2/Makefile.am @@ -0,0 +1,28 @@ +SWIG_SRC=../pysairedis.i +SOURCES=../pysairedis.h ../pysairedis.cpp + +pkgpython_PYTHON = pysairedis.py __init__.py +pkgpyexec_LTLIBRARIES = _pysairedis.la + +INCLUDE=-I../../SAI/inc -I../../SAI/meta -I../../SAI/experimental -I../../lib/inc -I.. + +_pysairedis_la_SOURCES = pysairedis_wrap.cpp $(SOURCES) +_pysairedis_la_CPPFLAGS = $(INCLUDE) -I/usr/include/python$(PYTHON_VERSION) $(AM_CPPFLAGS) $(CFLAGS_COMMON) \ + -Wno-cast-qual -Wno-shadow -Wno-redundant-decls -Wno-cast-function-type +_pysairedis_la_LDFLAGS = -module \ + -lhiredis -lswsscommon -lpthread \ + -L$(top_srcdir)/lib/src/.libs -lsairedis \ + -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta \ + -lzmq + +_pysairedis_la_LIBADD = $(PYTHON3_BLDLIBRARY) + +SWIG_FLAG = -Wall -c++ -python -keyword +if ARCH64 +SWIG_FLAG += -DSWIGWORDSIZE64 +endif + +pysairedis_wrap.cpp: $(SWIG_SRC) $(SOURCES) + $(SWIG) $(SWIG_FLAG) $(INCLUDE) -o $@ $< + +CLEANFILES = pysairedis_wrap.cpp diff --git a/pyext/py2/__init__.py b/pyext/py2/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pyext/py3/Makefile.am b/pyext/py3/Makefile.am new file mode 100644 index 000000000000..994ad81d4306 --- /dev/null +++ b/pyext/py3/Makefile.am @@ -0,0 +1,28 @@ +SWIG_SRC=../pysairedis.i +SOURCES=../pysairedis.h ../pysairedis.cpp + +pkgpython3_PYTHON = pysairedis.py __init__.py +pkgpy3exec_LTLIBRARIES = _pysairedis.la + +INCLUDE=-I../../SAI/inc -I../../SAI/meta -I../../SAI/experimental -I../../lib/inc -I.. + +_pysairedis_la_SOURCES = pysairedis_wrap.cpp $(SOURCES) +_pysairedis_la_CPPFLAGS = $(INCLUDE) -I/usr/include/python$(PYTHON3_VERSION) $(AM_CPPFLAGS) $(CFLAGS_COMMON) \ + -Wno-cast-qual -Wno-shadow -Wno-redundant-decls -Wno-cast-function-type +_pysairedis_la_LDFLAGS = -module \ + -lhiredis -lswsscommon -lpthread \ + -L$(top_srcdir)/lib/src/.libs -lsairedis \ + -L$(top_srcdir)/meta/.libs -lsaimetadata -lsaimeta \ + -lzmq + +_pysairedis_la_LIBADD = $(PYTHON3_BLDLIBRARY) + +SWIG_FLAG = -Wall -c++ -python -keyword +if ARCH64 +SWIG_FLAG += -DSWIGWORDSIZE64 +endif + +pysairedis_wrap.cpp: $(SWIG_SRC) $(SOURCES) + $(SWIG) $(SWIG_FLAG) $(INCLUDE) -o $@ $< + +CLEANFILES = pysairedis_wrap.cpp diff --git a/pyext/py3/__init__.py b/pyext/py3/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pyext/pysairedis.cpp b/pyext/pysairedis.cpp new file mode 100644 index 000000000000..c961507f1046 --- /dev/null +++ b/pyext/pysairedis.cpp @@ -0,0 +1,335 @@ +#include "pysairedis.h" + +#include "lib/inc/sairedis.h" +#include "swss/logger.h" + +#include "meta/sai_serialize.h" + +static std::map g_profileMap; +static std::map::iterator g_profileMapIterator = g_profileMap.begin(); + +static const char *profile_get_value ( + _In_ sai_switch_profile_id_t profile_id, + _In_ const char *variable) +{ + SWSS_LOG_ENTER(); + + auto it = g_profileMap.find(variable); + + if (it == g_profileMap.end()) + return NULL; + return it->second.c_str(); +} + +static int profile_get_next_value ( + _In_ sai_switch_profile_id_t profile_id, + _Out_ const char **variable, + _Out_ const char **value) +{ + SWSS_LOG_ENTER(); + + if (value == NULL) + { + // Restarts enumeration + g_profileMapIterator = g_profileMap.begin(); + } + else if (g_profileMapIterator == g_profileMap.end()) + { + return -1; + } + else + { + *variable = g_profileMapIterator->first.c_str(); + *value = g_profileMapIterator->second.c_str(); + g_profileMapIterator++; + } + + if (g_profileMapIterator != g_profileMap.end()) + return 0; + + return -1; +} + +static const sai_service_method_table_t g_smt = { + profile_get_value, + profile_get_next_value +}; + +sai_status_t sai_api_initialize( + _In_ uint64_t flags, + _In_ const std::map& profileMap) +{ + g_profileMap = profileMap; + g_profileMapIterator = g_profileMap.begin(); + + return sai_api_initialize(flags, &g_smt); +} + +sai_status_t sai_get_switch_api(sai_switch_api_t* out) +{ + sai_switch_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_SWITCH, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_lag_api(sai_lag_api_t* out) +{ + sai_lag_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_LAG, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_router_interface_api(sai_router_interface_api_t* out) +{ + sai_router_interface_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_ROUTER_INTERFACE, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_next_hop_api(sai_next_hop_api_t* out) +{ + sai_next_hop_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_NEXT_HOP, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_route_api(sai_route_api_t* out) +{ + sai_route_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_ROUTE, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_vlan_api(sai_vlan_api_t* out) +{ + sai_vlan_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_VLAN, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_status_t sai_get_fdb_api(sai_fdb_api_t* out) +{ + sai_fdb_api_t* api; + + sai_status_t status = sai_api_query(SAI_API_FDB, (void**)&api); + + if (status == SAI_STATUS_SUCCESS) + { + *out = *api; + } + + return status; +} + +sai_mac_t* sai_mac_t_from_string(const std::string& s) +{ + sai_mac_t *mac = (sai_mac_t*)calloc(1, sizeof(sai_mac_t)); + + sai_deserialize_mac(s, *mac); + + return mac; +} + +sai_ip_address_t* sai_ip_address_t_from_string(const std::string& s) +{ + sai_ip_address_t* ip = (sai_ip_address_t*)calloc(1, sizeof(sai_ip_address_t)); + + sai_deserialize_ip_address(s, *ip); + return ip; +} + +sai_ip_prefix_t* sai_ip_prefix_t_from_string(const std::string& s) +{ + sai_ip_prefix_t* ip = (sai_ip_prefix_t*)calloc(1, sizeof(sai_ip_prefix_t)); + + sai_deserialize_ip_prefix(s, *ip); + + return ip; +} + +// sai notification handling + +PyObject *py_convert_sai_fdb_event_notification_data_t_to_PyObject(const sai_fdb_event_notification_data_t*ntf); +PyObject *py_convert_sai_bfd_session_state_notification_t_to_PyObject(const sai_bfd_session_state_notification_t*ntf); +PyObject *py_convert_sai_port_oper_status_notification_t_to_PyObject(const sai_port_oper_status_notification_t*ntf); +PyObject *py_convert_sai_queue_deadlock_notification_data_t_to_PyObject(const sai_queue_deadlock_notification_data_t*ntf); + +static PyObject * py_fdb_event_notification = NULL; +static PyObject * py_port_state_change_notification = NULL; +static PyObject * py_queue_pfc_deadlock_notification = NULL; +static PyObject * py_switch_shutdown_request_notification = NULL; +static PyObject * py_switch_state_change_notification = NULL; + +void call_python(PyObject* callObject, PyObject* arglist) +{ + PyObject* result = PyObject_CallObject(callObject, arglist); + + if (result == NULL) + { + PyObject* pPyErr = PyErr_Occurred(); + + if (pPyErr) + { + PyErr_Print(); + return; + } + + SWSS_LOG_THROW("callback call failed"); + } + + Py_DECREF(result); +} + +static void sai_fdb_event_notification( + _In_ uint32_t count, + _In_ const sai_fdb_event_notification_data_t *data) +{ + PyObject* obj = py_convert_sai_fdb_event_notification_data_t_to_PyObject(data); + + PyObject* arglist = Py_BuildValue("(iO)", count, obj); + + call_python(py_fdb_event_notification, arglist); + + Py_DECREF(obj); + + Py_DECREF(arglist); +} + +static void sai_port_state_change_notification( + _In_ uint32_t count, + _In_ const sai_port_oper_status_notification_t *data) +{ + PyObject* obj = py_convert_sai_port_oper_status_notification_t_to_PyObject(data); + + PyObject* arglist = Py_BuildValue("(iO)", count, obj); + + call_python(py_port_state_change_notification, arglist); + + Py_DECREF(obj); + + Py_DECREF(arglist); +} + +static void sai_queue_pfc_deadlock_notification( + _In_ uint32_t count, + _In_ const sai_queue_deadlock_notification_data_t *data) +{ + PyObject* obj = py_convert_sai_queue_deadlock_notification_data_t_to_PyObject(data); + + PyObject* arglist = Py_BuildValue("(iO)", count, obj); + + call_python(py_queue_pfc_deadlock_notification, arglist); + + Py_DECREF(obj); + + Py_DECREF(arglist); +} + +static void sai_switch_shutdown_request_notification( + _In_ sai_object_id_t switch_id) +{ + PyObject* arglist = Py_BuildValue("(l)", switch_id); + + call_python(py_switch_shutdown_request_notification, arglist); + + Py_DECREF(arglist); +} + +static void sai_switch_state_change_notification( + _In_ sai_object_id_t switch_id, + _In_ sai_switch_oper_status_t switch_oper_status) +{ + PyObject* arglist = Py_BuildValue("(li)", switch_id, switch_oper_status); + + call_python(py_switch_state_change_notification, arglist); + + Py_DECREF(arglist); +} + +sai_pointer_t sai_get_notification_pointer( + sai_attr_id_t id, + PyObject*callback) +{ + if (!PyCallable_Check(callback)) + { + SWSS_LOG_THROW("second parameter must be python callable object"); + } + + Py_XINCREF(callback); // inc ref on current callback + + switch(id) + { + case SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY: + Py_XDECREF(py_switch_state_change_notification); + py_switch_state_change_notification = callback; + return (void*)&sai_switch_state_change_notification; + + case SAI_SWITCH_ATTR_SWITCH_SHUTDOWN_REQUEST_NOTIFY: + Py_XDECREF(py_switch_shutdown_request_notification); + py_switch_shutdown_request_notification = callback; + return (void*)&sai_switch_shutdown_request_notification; + + case SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY: + Py_XDECREF(py_fdb_event_notification); + py_fdb_event_notification = callback; + return (void*)&sai_fdb_event_notification; + + case SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY: + Py_XDECREF(py_port_state_change_notification); + py_port_state_change_notification = callback; + return (void*)&sai_port_state_change_notification; + + case SAI_SWITCH_ATTR_QUEUE_PFC_DEADLOCK_NOTIFY: + Py_XDECREF(py_queue_pfc_deadlock_notification); + py_queue_pfc_deadlock_notification = callback; + return (void*)&sai_queue_pfc_deadlock_notification; + + default: + Py_XDECREF(callback); + break; + } + + SWSS_LOG_THROW("notification attr id %d not supported", id); +} diff --git a/pyext/pysairedis.h b/pyext/pysairedis.h new file mode 100644 index 000000000000..84d0318e49af --- /dev/null +++ b/pyext/pysairedis.h @@ -0,0 +1,19 @@ + +#include + +extern "C" { +#include "sai.h" +#include "getapi.h" +} + +#include +#include + +sai_status_t sai_api_initialize( + uint64_t flags, + const std::map& profileMap); + +// will take python callback, and return C callback to set on notify attributes +sai_pointer_t sai_get_notification_pointer( + sai_attr_id_t id, + PyObject*callback); diff --git a/pyext/pysairedis.i b/pyext/pysairedis.i new file mode 100644 index 000000000000..c1b57a3a89a2 --- /dev/null +++ b/pyext/pysairedis.i @@ -0,0 +1,111 @@ +%module pysairedis + +%include "cpointer.i" +%include "carrays.i" + +%{ +#include "pysairedis.h" + +extern "C"{ +#include "sai.h" +#include "getapi.h" +} + +#include "sairedis.h" + +%} + +%include "std_string.i" +%include "std_map.i" + +namespace std { + %template(map_string_string) map; +} + +%include "pysairedis.h" + +%include "saitypes.h" +%include "sai.h" + +%include "getapi.h" + +%include "switch.h" +%include "lag.h" +%include "routerinterface.h" +%include "nexthop.h" +%include "route.h" +%include "vlan.h" +%include "fdb.h" + +%ignore sai_switch_api_t; +%ignore sai_lag_api_t; +%ignore sai_router_interface_api_t; +%ignore sai_next_hop_api_t; +%ignore sai_route_api_t; +%ignore sai_vlan_api_t; +%ignore sai_fdb_api_t; + +%include "saiswitch.h" +%include "sailag.h" +%include "sairouterinterface.h" +%include "sainexthop.h" +%include "sairoute.h" +%include "saivlan.h" +%include "saifdb.h" +%include "saiport.h" +%include "saibfd.h" +%include "saiqueue.h" + + +%include "sairedis.h" + +// helper functions + +%{ +sai_mac_t* sai_mac_t_from_string(const std::string& s); +sai_ip_address_t* sai_ip_address_t_from_string(const std::string& s); +sai_ip_prefix_t* sai_ip_prefix_t_from_string(const std::string& s); +%} + +sai_mac_t* sai_mac_t_from_string(const std::string& s); +sai_ip_address_t* sai_ip_address_t_from_string(const std::string& s); +sai_ip_prefix_t* sai_ip_prefix_t_from_string(const std::string& s); + +%newobject sai_mac_t_from_string; +%newobject sai_ip_address_t_from_string; +%newobject sai_ip_prefix_t_from_string; + +// array functions + +%include + +%array_functions(uint32_t, uint32_t_arr); +%pointer_functions(uint32_t, uint32_t_p); + +%array_functions(sai_object_id_t, sai_object_id_t_arr); +%pointer_functions(sai_object_id_t, sai_object_id_t_p); + +%array_functions(sai_attribute_t, sai_attribute_t_arr); +%pointer_functions(sai_attribute_t, sai_attribute_t_p); + +%array_functions(sai_bfd_session_state_notification_t, sai_bfd_session_state_notification_t_arr); +%pointer_functions(sai_bfd_session_state_notification_t, sai_bfd_session_state_notification_t_p); +%array_functions(sai_fdb_event_notification_data_t, sai_fdb_event_notification_data_t_arr); +%pointer_functions(sai_fdb_event_notification_data_t, sai_fdb_event_notification_data_t_p); +%array_functions(sai_port_oper_status_notification_t, sai_port_oper_status_notification_t_arr); +%pointer_functions(sai_port_oper_status_notification_t, sai_port_oper_status_notification_t_p); +%array_functions(sai_queue_deadlock_notification_data_t, sai_queue_deadlock_notification_data_t_arr); +%pointer_functions(sai_queue_deadlock_notification_data_t, sai_queue_deadlock_notification_data_t_p); + +%{ +PyObject *py_convert_sai_fdb_event_notification_data_t_to_PyObject(const sai_fdb_event_notification_data_t*ntf) +{ return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_fdb_event_notification_data_t, 0 | 0); } +PyObject *py_convert_sai_bfd_session_state_notification_t_to_PyObject(const sai_bfd_session_state_notification_t*ntf) +{ return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_bfd_session_state_notification_t, 0 | 0); } +PyObject *py_convert_sai_port_oper_status_notification_t_to_PyObject(const sai_port_oper_status_notification_t*ntf) +{ return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_port_oper_status_notification_t, 0 | 0); } +PyObject *py_convert_sai_queue_deadlock_notification_data_t_to_PyObject(const sai_queue_deadlock_notification_data_t*ntf) +{ return SWIG_NewPointerObj((void*)ntf, SWIGTYPE_p__sai_queue_deadlock_notification_data_t, 0 | 0); } +%} + + diff --git a/pyext/route.h b/pyext/route.h new file mode 100644 index 000000000000..3622a5269af3 --- /dev/null +++ b/pyext/route.h @@ -0,0 +1,52 @@ + +// TODO auto generate + +typedef struct _sai_route_api_t +{ + sai_status_t create_route_entry( + _In_ const sai_route_entry_t *route_entry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_route_entry( + _In_ const sai_route_entry_t *route_entry); + + sai_status_t set_route_entry_attribute( + _In_ const sai_route_entry_t *route_entry, + _In_ const sai_attribute_t *attr); + + sai_status_t get_route_entry_attribute( + _In_ const sai_route_entry_t *route_entry, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t create_route_entries( + _In_ uint32_t object_count, + _In_ const sai_route_entry_t *route_entry, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t remove_route_entries( + _In_ uint32_t object_count, + _In_ const sai_route_entry_t *route_entry, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t set_route_entries_attribute( + _In_ uint32_t object_count, + _In_ const sai_route_entry_t *route_entry, + _In_ const sai_attribute_t *attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t get_route_entries_attribute( + _In_ uint32_t object_count, + _In_ const sai_route_entry_t *route_entry, + _In_ const uint32_t *attr_count, + _Inout_ sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + +} sai_route_api_t; diff --git a/pyext/routerinterface.h b/pyext/routerinterface.h new file mode 100644 index 000000000000..d3c8f46e4543 --- /dev/null +++ b/pyext/routerinterface.h @@ -0,0 +1,42 @@ + +// TODO auto generate + +typedef struct _sai_router_interface_api_t +{ + sai_status_t create_router_interface( + _Out_ sai_object_id_t *router_interface_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_router_interface( + _In_ sai_object_id_t router_interface_id); + + sai_status_t set_router_interface_attribute( + _In_ sai_object_id_t router_interface_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_router_interface_attribute( + _In_ sai_object_id_t router_interface_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t get_router_interface_stats( + _In_ sai_object_id_t router_interface_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _Out_ uint64_t *counters); + + sai_status_t get_router_interface_stats_ext( + _In_ sai_object_id_t router_interface_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Out_ uint64_t *counters); + + sai_status_t clear_router_interface_stats( + _In_ sai_object_id_t router_interface_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids); + +} sai_router_interface_api_t; diff --git a/pyext/switch.h b/pyext/switch.h new file mode 100644 index 000000000000..e1e527e1454e --- /dev/null +++ b/pyext/switch.h @@ -0,0 +1,56 @@ + +// TODO auto generate + +typedef struct _sai_switch_api_t +{ + sai_status_t create_switch( + _Out_ sai_object_id_t *switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_switch( + _In_ sai_object_id_t switch_id); + + sai_status_t set_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t get_switch_stats( + _In_ sai_object_id_t switch_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _Out_ uint64_t *counters); + + sai_status_t get_switch_stats_ext( + _In_ sai_object_id_t switch_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Out_ uint64_t *counters); + + sai_status_t clear_switch_stats( + _In_ sai_object_id_t switch_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids); + + sai_status_t switch_mdio_read( + _In_ sai_object_id_t switch_id, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _Out_ uint32_t *reg_val); + + sai_status_t switch_mdio_write( + _In_ sai_object_id_t switch_id, + _In_ uint32_t device_addr, + _In_ uint32_t start_reg_addr, + _In_ uint32_t number_of_registers, + _In_ const uint32_t *reg_val); + +} sai_switch_api_t; + diff --git a/pyext/test.py b/pyext/test.py new file mode 100755 index 000000000000..52d0ea223ffd --- /dev/null +++ b/pyext/test.py @@ -0,0 +1,345 @@ +#!/usr/bin/python + +# redis-cli FLUSHALL +# run syncd: syncd -SUu -z redis_sync -p vsprofile.ini + +#from pysairedis import * +import pysairedis + +def switch_shutdown_request_notification(switch_id): + print " - switch shutdown request" + print " * swid: " + hex(switch_id) + +def switch_state_change_notification(switch_id, switch_oper_status): + print " - switch state change" + print " * swid: " + hex(switch_id) + print " * oper_status: " + str(switch_oper_status) + +def port_state_change_notification(count, port_oper_status): + print " - port state change" + print " * count: " + str(count) + + for n in range(0,count): + item = pysairedis.sai_port_oper_status_notification_t_arr_getitem(port_oper_status, n) + print " * port_id: " + hex(item.port_id) + print " * port_state: " + str(item.port_state) + +def fdb_event_notification(count, data): + print " - fdb event" + print " * count: " + str(count) + + for n in range(0,count): + item = pysairedis.sai_fdb_event_notification_data_t_arr_getitem(data, n) + print " * event_type: " + str(item.event_type) + print " * fdb_entry" + str(item.fdb_entry) + print " * attr_count: " + str(item.attr_count) + +profileMap = dict() + +profileMap["SAI_WARM_BOOT_READ_FILE"] = "./sai_warmboot.bin" +profileMap["SAI_WARM_BOOT_WRITE_FILE"] = "./sai_warmboot.bin" + +status = pysairedis.sai_api_initialize(0,profileMap) +print "initialize: " + str(status) + +switch_api = pysairedis.sai_switch_api_t() + +status = pysairedis.sai_get_switch_api(switch_api) +print "sai_get_switch_api: " + str(status) + +attr = pysairedis.sai_attribute_t(); + +attr.id = pysairedis.SAI_REDIS_SWITCH_ATTR_RECORD +attr.value.booldata = True + +status = switch_api.set_switch_attribute(0, attr) +print "set record mode: " + str(status) + +attr.id = pysairedis.SAI_REDIS_SWITCH_ATTR_SYNC_OPERATION_RESPONSE_TIMEOUT +attr.value.u64 = 3000 + +status = switch_api.set_switch_attribute(0, attr) +print "timeout: " + str(status) + +attr.id = pysairedis.SAI_REDIS_SWITCH_ATTR_REDIS_COMMUNICATION_MODE +attr.value.s32 = pysairedis.SAI_REDIS_COMMUNICATION_MODE_REDIS_SYNC + +status = switch_api.set_switch_attribute(0, attr) +print "set communication mode: " + str(status) + +attr.id = pysairedis.SAI_REDIS_SWITCH_ATTR_NOTIFY_SYNCD +attr.value.s32 = pysairedis.SAI_REDIS_NOTIFY_SYNCD_INIT_VIEW + +status = switch_api.set_switch_attribute(0, attr) +print "init view: " + str(status) + +poid = pysairedis.new_sai_object_id_t_p() + +attrs = pysairedis.new_sai_attribute_t_arr(6) + +attr.id = pysairedis.SAI_SWITCH_ATTR_INIT_SWITCH +attr.value.booldata = True +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +attr.id = pysairedis.SAI_SWITCH_ATTR_SRC_MAC_ADDRESS +# TODO +#attr.value.mac = "90:B1:1C:F4:A8:53" +pysairedis.sai_attribute_t_arr_setitem(attrs, 1, attr) + +# set notification callbacks + +attr.id = pysairedis.SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY +attr.value.ptr = pysairedis.sai_get_notification_pointer(pysairedis.SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY, switch_state_change_notification) +pysairedis.sai_attribute_t_arr_setitem(attrs, 2, attr) + +attr.id = pysairedis.SAI_SWITCH_ATTR_SWITCH_SHUTDOWN_REQUEST_NOTIFY +attr.value.ptr = pysairedis.sai_get_notification_pointer(pysairedis.SAI_SWITCH_ATTR_SWITCH_SHUTDOWN_REQUEST_NOTIFY, switch_shutdown_request_notification) +pysairedis.sai_attribute_t_arr_setitem(attrs, 3, attr) + +attr.id = pysairedis.SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY +attr.value.ptr = pysairedis.sai_get_notification_pointer(pysairedis.SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY, fdb_event_notification) +pysairedis.sai_attribute_t_arr_setitem(attrs, 4, attr) + +attr.id = pysairedis.SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY +attr.value.ptr = pysairedis.sai_get_notification_pointer(pysairedis.SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY, port_state_change_notification) +pysairedis.sai_attribute_t_arr_setitem(attrs, 5, attr) + +status = switch_api.create_switch(poid, 6, attrs) +print "create_switch: " + str(status) + +swid = pysairedis.sai_object_id_t_p_value(poid) + +print "swid: " + hex(swid) + +pysairedis.delete_sai_attribute_t_arr(attrs) + +attr.id = pysairedis.SAI_REDIS_SWITCH_ATTR_NOTIFY_SYNCD +attr.value.s32 = pysairedis.SAI_REDIS_NOTIFY_SYNCD_APPLY_VIEW + +status = switch_api.set_switch_attribute(swid, attr) +print "apply view: " + str(status) + +attr.id = pysairedis.SAI_SWITCH_ATTR_PORT_LIST +attr.value.objlist.count = 128 +attr.value.objlist.list = pysairedis.new_sai_object_id_t_arr(128) + +status = switch_api.get_switch_attribute(swid, 1, attr); +print "get port list: " + str(status) +print "ports count: " + str(attr.value.objlist.count) + +portlist = [] + +for n in range(0, attr.value.objlist.count): + port = pysairedis.sai_object_id_t_arr_getitem(attr.value.objlist.list, n) + portlist.append(port) + +pysairedis.delete_sai_object_id_t_arr(attr.value.objlist.list) + +print "portlist: " + str(portlist) + +print "portlist[0]: " + hex(portlist[0]) + +attr.id = pysairedis.SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID + +status = switch_api.get_switch_attribute(swid, 1, attr); +print "get default virtual router: " + str(status) + +vrid = attr.value.oid + +print "vrid: " + hex(vrid) + +lag_api = pysairedis.sai_lag_api_t() + +status = pysairedis.sai_get_lag_api(lag_api) +print "sai_get_lag_api: " + str(status) + +poid = pysairedis.new_sai_object_id_t_p() +#attrs = pysairedis.new_sai_attribute_t_arr(2) + +status = lag_api.create_lag(poid, swid, 0, None) +print "create lag: " + str(status) + +lagid = pysairedis.sai_object_id_t_p_value(poid) + +pysairedis.delete_sai_object_id_t_p(poid) + +print "lagid: " + hex(lagid) + +router_interface_api = pysairedis.sai_router_interface_api_t() + +status = pysairedis.sai_get_router_interface_api(router_interface_api) +print "sai_get_router_interface_api: " + str(status) + +poid = pysairedis.new_sai_object_id_t_p() +attrs = pysairedis.new_sai_attribute_t_arr(3) + +attr.id = pysairedis.SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID +attr.value.oid = vrid +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +attr.id = pysairedis.SAI_ROUTER_INTERFACE_ATTR_TYPE +attr.value.s32 = pysairedis.SAI_ROUTER_INTERFACE_TYPE_PORT +pysairedis.sai_attribute_t_arr_setitem(attrs, 1, attr) + +attr.id = pysairedis.SAI_ROUTER_INTERFACE_ATTR_PORT_ID +attr.value.oid = portlist[0] +pysairedis.sai_attribute_t_arr_setitem(attrs, 2, attr) + +status = router_interface_api.create_router_interface(poid, swid, 3, attrs) +print "create router interface: " + str(status) + +rifid = pysairedis.sai_object_id_t_p_value(poid) + +pysairedis.delete_sai_object_id_t_p(poid) +pysairedis.delete_sai_attribute_t_arr(attrs) + +print "rifid: " + hex(rifid) + +next_hop_api = pysairedis.sai_next_hop_api_t() + +status = pysairedis.sai_get_next_hop_api(next_hop_api) +print "sai_get_next_hop_api: " + str(status) + +poid = pysairedis.new_sai_object_id_t_p() +attrs = pysairedis.new_sai_attribute_t_arr(3) + +attr.id = pysairedis.SAI_NEXT_HOP_ATTR_TYPE +attr.value.s32 = pysairedis.SAI_NEXT_HOP_TYPE_IP +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +attr.id = pysairedis.SAI_NEXT_HOP_ATTR_IP +attr.value.ipaddr = pysairedis.sai_ip_address_t_from_string("10.0.0.1") +pysairedis.sai_attribute_t_arr_setitem(attrs, 1, attr) + +attr.id = pysairedis.SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID +attr.value.oid = rifid +pysairedis.sai_attribute_t_arr_setitem(attrs, 2, attr) + +status = next_hop_api.create_next_hop(poid, swid, 3, attrs) +print "create next hop: " + str(status) + +nexthopid = pysairedis.sai_object_id_t_p_value(poid) + +pysairedis.delete_sai_object_id_t_p(poid) +pysairedis.delete_sai_attribute_t_arr(attrs) + +print "nexthopid: " + hex(nexthopid) + +route_api = pysairedis.sai_route_api_t() + +status = pysairedis.sai_get_route_api(route_api) +print "sai_get_route_api: " + str(status) + +attrs = pysairedis.new_sai_attribute_t_arr(1) + +attr.id = pysairedis.SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION +attr.value.s32 = pysairedis.SAI_PACKET_ACTION_DROP +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +re = pysairedis.sai_route_entry_t() + +re.destination = pysairedis.sai_ip_prefix_t_from_string("0.0.0.0/0") +re.switch_id = swid +re.vr_id = vrid + +status = route_api.create_route_entry(re, 1, attrs) +print "create default route entry: " + str(status) + +pysairedis.delete_sai_attribute_t_arr(attrs) + +attrs = pysairedis.new_sai_attribute_t_arr(1) + +attr.id = pysairedis.SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID +attr.value.oid = nexthopid +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +re = pysairedis.sai_route_entry_t() + +re.destination = pysairedis.sai_ip_prefix_t_from_string("100.1.0.1/32") +re.switch_id = swid +re.vr_id = vrid + +status = route_api.create_route_entry(re, 1, attrs) +print "create route entry: " + str(status) + +pysairedis.delete_sai_attribute_t_arr(attrs) + +vlan_api = pysairedis.sai_vlan_api_t() + +status = pysairedis.sai_get_vlan_api(vlan_api) +print "sai_get_vlan_api: " + str(status) + +poid = pysairedis.new_sai_object_id_t_p() +attrs = pysairedis.new_sai_attribute_t_arr(1) + +attr.id = pysairedis.SAI_VLAN_ATTR_VLAN_ID +attr.value.u16 = 11 +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +status = vlan_api.create_vlan(poid, swid, 1, attrs) +print "create vlan: " + str(status) + +vlanid = pysairedis.sai_object_id_t_p_value(poid) + +pysairedis.delete_sai_object_id_t_p(poid) +pysairedis.delete_sai_attribute_t_arr(attrs) + +print "vlanid: " + hex(vlanid) + +fdb_api = pysairedis.sai_fdb_api_t() + +status = pysairedis.sai_get_fdb_api(fdb_api) +print "sai_get_fdb_api: " + str(status) + +attrs = pysairedis.new_sai_attribute_t_arr(2) + +attr.id = pysairedis.SAI_FDB_ENTRY_ATTR_TYPE +attr.value.s32 = pysairedis.SAI_FDB_ENTRY_TYPE_DYNAMIC +pysairedis.sai_attribute_t_arr_setitem(attrs, 0, attr) + +attr.id = pysairedis.SAI_FDB_ENTRY_ATTR_PACKET_ACTION +attr.value.s32 = pysairedis.SAI_PACKET_ACTION_FORWARD +pysairedis.sai_attribute_t_arr_setitem(attrs, 1, attr) + +fe = pysairedis.sai_fdb_entry_t() + +# TODO +#fe.mac_address = pysairedis.sai_mac_t_from_string("FE:54:00:B3:06:8C") +fe.switch_id = swid +fe.bv_id = vlanid + +status = fdb_api.create_fdb_entry(fe, 2, attrs) +print "create default fdb entry: " + str(status) + +pysairedis.delete_sai_attribute_t_arr(attrs) + +status = fdb_api.remove_fdb_entry(fe) +print "remove fdb entry: " + str(status) + +attr.id = pysairedis.SAI_VLAN_ATTR_MAX_LEARNED_ADDRESSES +attr.value.u16 = 32 + +status = vlan_api.set_vlan_attribute(vlanid, attr) +print "set vlan attribute: " + str(status) + +r = vlan_api.remove_vlan(vlanid) +print "remove vlan: " + str(status) + +attr.id = pysairedis.SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION +attr.value.s32 = pysairedis.SAI_PACKET_ACTION_FORWARD + +status = route_api.set_route_entry_attribute(re, attr) +print "set route entry: " + str(status) + +attr.id = pysairedis.SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION + +status = route_api.get_route_entry_attribute(re, 1, attr) +print "get route entry packet action: " + str(status) + +print "packet action: " + str(attr.value.s32) + +status = route_api.remove_route_entry(re) +print "remove route entry: " + str(status) + +status = pysairedis.sai_api_uninitialize() +print "uninitialize: " + str(status) diff --git a/pyext/vlan.h b/pyext/vlan.h new file mode 100644 index 000000000000..7c7f8f779cf8 --- /dev/null +++ b/pyext/vlan.h @@ -0,0 +1,76 @@ + +// TODO auto generate + +typedef struct _sai_vlan_api_t +{ + sai_status_t create_vlan( + _Out_ sai_object_id_t *vlan_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_vlan( + _In_ sai_object_id_t vlan_id); + + sai_status_t set_vlan_attribute( + _In_ sai_object_id_t vlan_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_vlan_attribute( + _In_ sai_object_id_t vlan_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t create_vlan_member( + _Out_ sai_object_id_t *vlan_member_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove_vlan_member( + _In_ sai_object_id_t vlan_member_id); + + sai_status_t set_vlan_member_attribute( + _In_ sai_object_id_t vlan_member_id, + _In_ const sai_attribute_t *attr); + + sai_status_t get_vlan_member_attribute( + _In_ sai_object_id_t vlan_member_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); + + sai_status_t create_vlan_members( + _In_ sai_object_id_t switch_id, + _In_ uint32_t object_count, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_object_id_t *object_id, + _Out_ sai_status_t *object_statuses); + + sai_status_t remove_vlan_members( + _In_ uint32_t object_count, + _In_ const sai_object_id_t *object_id, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses); + + sai_status_t get_vlan_stats( + _In_ sai_object_id_t vlan_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _Out_ uint64_t *counters); + + sai_status_t get_vlan_stats_ext( + _In_ sai_object_id_t vlan_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Out_ uint64_t *counters); + + sai_status_t clear_vlan_stats( + _In_ sai_object_id_t vlan_id, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids); + +} sai_vlan_api_t; + diff --git a/tests/aspell.en.pws b/tests/aspell.en.pws index d6370a6d6e14..8ba60363ae45 100644 --- a/tests/aspell.en.pws +++ b/tests/aspell.en.pws @@ -84,6 +84,7 @@ ETERM eth ethernet ethX +extern fastfast fdb FDB @@ -287,6 +288,7 @@ torvalds ttl tx TXSC +typedef uint uncomment uninitialize diff --git a/tests/aspellcheck.pl b/tests/aspellcheck.pl index ed1af79d0d97..73c2609a7e3b 100755 --- a/tests/aspellcheck.pl +++ b/tests/aspellcheck.pl @@ -149,6 +149,8 @@ sub RunAspell next if $file =~ m!/SAI/!; next if $file =~ m!/debian/!; next if $file =~ m!/config.h!; + next if $file =~ m!/python/.+wrap.cpp!; + next if $file =~ m!/pyext/.+wrap.cpp!; my $data = ReadFile $file; diff --git a/tests/swsslogentercheck.pl b/tests/swsslogentercheck.pl index 437bbf28007e..458b98dbba32 100755 --- a/tests/swsslogentercheck.pl +++ b/tests/swsslogentercheck.pl @@ -27,6 +27,8 @@ sub ReadFile next if $arg =~ m!/SAI/!; next if $arg =~ m!/debian/!; + next if $arg =~ m!/pyext/!; + next if $arg =~ m!/python/!; my $returnType = '([:_a-z0-9<>]+)(?:\s*[*&]\s*|\s+)'; my $methodName = '(~?\w+|\w+::\w+)';