stub.pl (328 lines of code) (raw):

#!/usr/bin/perl use strict; use warnings; use diagnostics; use sort 'stable'; use Getopt::Std; use Data::Dumper; use Term::ANSIColor; my %options = (); getopts("d:c:n:f:s:", \%options); my $optionSaiDir = $options{d} if defined $options{d}; my $optionClass = $options{c} if defined $options{c}; my $optionNamespace = $options{n} if defined $options{n}; my $optionFileName = $options{f} if defined $options{f}; my $optionStub = $options{s} if defined $options{s}; my $STUB = $optionStub; my $DATA = ""; my @OBJECT_TYPES = (); my %objectTypes = (); my @APIS = (); my @FUNCTIONS = (); my %FUNCTIONS = (); my @globalApis = (); my @apiStructs = (); my %apiStructs = (); my %ENTRIES = (); my $SOURCE_CONTENT = ""; my $warnings = 0; my $errors = 0; sub LogInfo { print color('bright_green') . "@_" . color('reset') . "\n"; } sub LogWarning { $warnings++; print color('bright_yellow') . "WARNING: @_" . color('reset') . "\n"; } sub LogError { $errors++; print color('bright_red') . "ERROR: @_" . color('reset') . "\n"; exit 1; } sub WriteFile { my ($file, $content) = @_; open (F, ">", $file) or die "$0: open $file $!"; print F $content; close F; } sub Write { my $content = shift; my $ident = ""; #GetIdent($content); my $line = $ident . $content . "\n"; $line = "\n" if $content eq ""; $SOURCE_CONTENT .= $line; } sub GetFunctionCamelCaseName { my $fun = shift; $fun =~ s/^sai_//; my @tokens = split/_/,$fun; @tokens = map{ucfirst}@tokens; shift @tokens if $tokens[0] eq "api"; $tokens[0] = lcfirst $tokens[0]; $fun = join("",@tokens); return $fun; } sub GetData { $DATA = `cat $optionSaiDir/inc/sai*.h $optionSaiDir/experimental/sai*.h`; } sub SanitizeData { $DATA =~ s/SAI_OBJECT_TYPE_\w*(START|END|NULL|MAX)//gms; $DATA =~ s/SAI_API_\w*(START|END|UNSPECIFIED|MAX|EXTENSIONS_RANGE_BASE)//gms; } sub ExtractData { @OBJECT_TYPES = $DATA =~ /^\s+SAI_OBJECT_TYPE\_(\w+)/gms; @APIS = $DATA =~ /^\s+SAI_API\_(\w+)/gms; for my $ot (@OBJECT_TYPES) { $objectTypes{lc$ot} = $ot; } @FUNCTIONS = $DATA =~ /(typedef sai_status_t \(\*(?:sai_\w+_fn)\).*?\))/gms; @globalApis = $DATA =~ /^((?:sai_\w+)\s+(?:sai_\w+).+?\))/gms; for my $fun (@FUNCTIONS) { next if not $fun =~ /sai_\w+\s+.*?(sai_\w+)/gms; $FUNCTIONS{$1} = $fun; } @apiStructs = $DATA =~ /(_sai_\w+_api_t.+?sai_\w+_api_t)/gms; for my $struct (@apiStructs) { next if not $struct =~ /sai_(\w+)_api_t/; $apiStructs{$1} = $struct; } my @entries = $DATA =~ /\bsai_(\w+_entry)_t\b/gms; for my $e (@entries) { $ENTRIES{uc$e} = $e; } } sub Entry { my $i = shift; $i =~ s/entries/entry/; return $i; } sub GetFunctionName { my $fun = shift; my $OT = ""; my $bulk = 0; my $entry = 0; if ($fun =~ /(get|clear)_(\w+)_(stats(_ext)?)/ and defined $objectTypes{$2}) { $OT = $objectTypes{$2}; $fun = "$1_$3"; } elsif ($fun =~ /(create|remove|set|get)_(\w+_entries)/ and defined $objectTypes{Entry($2)}) { $bulk = 1; $OT = $objectTypes{Entry($2)}; $fun = "bulk_$1"; } elsif ($fun =~ /(set|get)_(\w+)s_attribute/ and defined $objectTypes{$2}) { $bulk = 1; $OT = $objectTypes{$2}; $fun = "bulk_$1"; } elsif ($fun =~ /(set|get)_(\w+)_attribute/ and defined $objectTypes{$2}) { $OT = $objectTypes{$2}; $fun = "$1"; } elsif ($fun =~ /(create|remove|set|get)_(\w+)s(_attribute)?/ and defined $objectTypes{$2}) { $bulk = 1; $OT = $objectTypes{$2}; $fun = "bulk_$1"; } elsif ($fun =~ /(create|remove|set|get)_(\w+)(_attribute)?/ and defined $objectTypes{$2}) { $OT = $objectTypes{$2}; $fun = "$1"; } elsif ($fun =~ /(create|remove|set|get)_(\w+)(_attribute)?/ and defined $objectTypes{$2}) { $OT = $objectTypes{$2}; $fun = "$1"; } else { LogInfo "Unique function $fun"; } $entry = 1 if defined $ENTRIES{$OT}; my $f = GetFunctionCamelCaseName($fun); return ($OT, $f, $entry, $bulk); } sub CreateApiStricts() { Write ""; Write "/* ==== API STRUCTS === */"; Write ""; for my $API (@APIS) { my $api = lc $API; Write ""; Write "/* SAI APIS for $API */"; Write ""; my $struct = $apiStructs{$api}; LogError "api $api not found" if not defined $struct; while ($struct =~ /(sai_\w+_fn)\s+(\w+)/gms) { my $type = $1; my $funname = $2; my $fun = $FUNCTIONS{$type}; LogError "function $fun not found" if not defined $fun; next if not $fun =~ /(sai_\w+).+\((.+?)\)/gms; my $rettype = $1; my $params = $2; my @par = $params =~ /(\w+,|\w+$)/gms; my ($OT, $fname, $entry, $bulk) = GetFunctionName($funname); $par[0] = "switch_id,SAI_NULL_OBJECT_ID," if $OT eq "SWITCH" and $bulk == 0 and $fname eq "create"; Write "static $rettype ${STUB}_$funname($params)"; Write "{"; Write " SWSS_LOG_ENTER();"; Write ""; if ($fname =~ /(clearPortAllStats|removeAllNeighborEntries|recvHostifPacket|sendHostifPacket|allocateHostifPacket|freeHostifPacket)/) { Write " SWSS_LOG_ERROR(\"FIXME, no implementation for $fname!\");"; Write " return SAI_STATUS_NOT_IMPLEMENTED;"; Write "}"; next; } Write " return $STUB" . "->$fname(@par);" if $OT eq ""; Write " return $STUB" . "->$fname(@par);" if $OT ne "" and $bulk == 1 and $entry == 1; Write " return $STUB" . "->$fname(@par);" if $OT ne "" and $bulk == 0 and $entry == 1; Write " return $STUB" . "->$fname((sai_object_type_t)(SAI_OBJECT_TYPE_$OT),@par);" if $OT ne "" and $bulk == 0 and $entry == 0; Write " return $STUB" . "->$fname((sai_object_type_t)(SAI_OBJECT_TYPE_$OT),@par);" if $OT ne "" and $bulk == 1 and $entry == 0; Write "}"; Write ""; } Write "static sai_${api}_api_t ${STUB}_${api} = {"; while ($struct =~ /(sai_\w+_fn)\s+(\w+)/gms) { my $type = $1; my $funname = $2; Write " .$funname = ${STUB}_$funname,"; } Write "};"; Write ""; } } sub CreateHeader { Write ""; Write "/* DO NOT MODIFY, FILE AUTO GENERATED */"; Write ""; Write "extern \"C\" {"; Write "#include \"sai.h\""; Write "#include \"saiextensions.h\""; Write "}"; Write "#include \"meta/SaiInterface.h\""; Write "#include \"$optionClass.h\""; Write "#include \"swss/logger.h\""; Write "#include <memory>"; Write ""; Write "static std::shared_ptr<sairedis::SaiInterface> $STUB = std::make_shared<$optionNamespace" . "::$optionClass>();"; Write "" } sub CreateApiQuery { Write ""; Write "/* ==== API QUERY === */"; Write ""; Write "sai_status_t sai_api_query("; Write " _In_ sai_api_t api,"; Write " _Out_ void** api_method_table)"; Write "{"; Write " SWSS_LOG_ENTER();"; Write ""; Write " if (api_method_table == NULL)"; Write " {"; Write " SWSS_LOG_ERROR(\"NULL method table passed to SAI API initialize\");"; Write ""; Write " return SAI_STATUS_INVALID_PARAMETER;"; Write " }"; Write ""; Write " if (api == SAI_API_UNSPECIFIED)"; Write " {"; Write " SWSS_LOG_ERROR(\"api ID is unspecified api\");"; Write ""; Write " return SAI_STATUS_INVALID_PARAMETER;"; Write " }"; Write ""; Write " switch((int)api)"; Write " {"; for my $API (@APIS) { my $api = lc $API; Write " case SAI_API_$API:"; Write " *api_method_table = (void**)&${STUB}_${api};"; Write " return SAI_STATUS_SUCCESS;"; } Write " default:"; Write " break;"; Write " }"; Write ""; Write " SWSS_LOG_ERROR(\"Invalid API type %d\", api);"; Write ""; Write " return SAI_STATUS_INVALID_PARAMETER;"; Write "}"; Write ""; } sub CreateGlobalApis { Write ""; Write "/* ==== GLOBAL APIS === */"; Write ""; for my $api (sort @globalApis) { next if not $api =~ /(sai_\w+)\s+(sai_\w+).*\((.+?)\)/gms; my $rettype = $1; my $funname = $2; my $params = $3; next if $funname eq "sai_api_query"; my @par = $params =~ /(\w+,|\w+$)/gms; my $fun = GetFunctionCamelCaseName($funname); $par[0] = "" if $par[0] eq "void"; Write "$rettype $funname($params)"; Write "{"; Write " SWSS_LOG_ENTER();"; Write ""; if ($fun =~ /(bulkObjectClearStats|bulkObjectGetStats|dbgGenerateDump|getMaximumAttributeCount|getObjectKey|bulkGetAttribute|dbgGenerateDump|tamTelemetryGetData|getObjectCount|queryObjectStage)/) { Write " SWSS_LOG_ERROR(\"FIXME, no implementation for $fun!\");"; Write " return SAI_STATUS_NOT_IMPLEMENTED;"; Write "}"; next; } Write " return $STUB" . "->$fun(@par);"; Write "}"; Write ""; } } # # MAIN # LogError "Option SaiDir not specifird (-d)" if not defined $optionSaiDir; LogError "Option Class not specifird (-c)" if not defined $optionClass; LogError "Option Namespace not specifird (-n)" if not defined $optionNamespace; LogError "Option FileName not specifird (-f)" if not defined $optionFileName; LogError "Option Stub not specifird (-s)" if not defined $optionStub; LogInfo "optionSaiDir = $optionSaiDir "; LogInfo "optionClass = $optionClass "; LogInfo "optionNamespace = $optionNamespace"; LogInfo "optionFileName = $optionFileName "; LogInfo "optionStub = $optionStub "; GetData(); SanitizeData(); ExtractData(); CreateHeader(); CreateApiStricts(); CreateApiQuery(); CreateGlobalApis(); WriteFile($optionFileName,$SOURCE_CONTENT);