2023-02-06 10:34:23 +08:00
# include <time.h>
# include <assert.h>
# include <cjson/cJSON.h>
# include <MESA/Maat_rule.h>
# include <MESA/MESA_prof_load.h>
# include "health_check.h"
# include "raw_packet.h"
# include "policy.h"
# include "utils.h"
# include "log.h"
/******************************************************************************
* Struct policy_enforcer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum input_mode
{
MAAT_INPUT_JSON = 0 ,
MAAT_INPUT_REDIS = 1 ,
MAAT_INPUT_FILE = 2 ,
} ;
struct policy_config
{
enum input_mode input_mode ;
int stat_switch ;
int perf_switch ;
int scan_detail ;
int deferred_load ;
int effect_interval_ms ;
char device_group [ 32 ] ;
char stat_file [ 2048 ] ;
char table_info [ 2048 ] ;
char accept_tags [ 2048 ] ;
char accept_path [ 2048 ] ;
char inc_cfg_dir [ 2048 ] ;
char ful_cfg_dir [ 2048 ] ;
char json_cfg_file [ 2048 ] ;
char foreign_cont_dir [ 2048 ] ;
int redis_db_idx ;
char redis_server [ 2048 ] ;
char redis_port_range [ 2048 ] ;
} ;
struct policy_enforcer
{
struct policy_config config ;
Maat_feather_t maat ;
int compile_table_id ; // SERVICE_CHAINING_COMPILE table id
int sff_table_id ; // SERVICE_FUNCTION_FORWARDER_PROFILE table id
int sf_table_id ; // SERVICE_FUNCTION_PROFILE table id
} ;
/******************************************************************************
* Struct chaining_param
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct chaining_param
{
int policy_id ;
int ref_cnt ;
enum traffic_type traffic_type ;
int * sff_profile_ids ;
int sff_profile_ids_num ;
} ;
/******************************************************************************
* Struct sff_param
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum failure_action
{
FAILURE_ACTION_BYPASS = 1 ,
FAILURE_ACTION_BLOCK = 2 ,
FAILURE_ACTION_RE_DISPATCH = 3 ,
} ;
enum unavailable_action
{
UNAVAILABLE_ACTION_BYPASSS = 1 ,
UNAVAILABLE_ACTION_BLOCK = 2 ,
} ;
enum ldbc_localization
{
LDBC_LOCALIZATION_NEARBY = 1 ,
LDBC_LOCALIZATION_GLOBAL = 2 ,
} ;
struct exception
{
enum failure_action fail_action ;
enum unavailable_action unavail_action ;
int health_service_func_lt ;
} ;
struct load_balance
{
enum ldbc_method method ;
enum ldbc_localization localiza ;
} ;
struct sff_param
{
int sff_profile_id ;
int sff_ref_cnt ;
enum forward_type sff_forward_type ;
struct load_balance sff_ldbc ;
struct exception sff_exception ;
int * sf_profile_ids ;
int sf_profile_ids_num ;
} ;
/******************************************************************************
* Struct sf_param
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum admin_status
{
ADMMIN_STATUS_ACTIVE = 1 ,
ADMMIN_STATUS_INACTIVE = 2 ,
} ;
struct sf_param
{
int sf_profile_id ;
int sf_ref_cnt ;
char sf_device_group [ 32 ] ;
enum admin_status sf_admin_status ;
struct connectivity sf_connectivity ;
struct health_check sf_health_check ;
} ;
/******************************************************************************
* Private API
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * traffic_type_to_string ( enum traffic_type traffic_type )
{
switch ( traffic_type )
{
case TRAFFIC_TYPE_NONE :
return " none " ;
case TRAFFIC_TYPE_RAW :
return " raw " ;
case TRAFFIC_TYPE_DECRYPTED :
return " decrypted " ;
default :
return " unknown " ;
}
}
static const char * forward_type_to_string ( enum forward_type forward_type )
{
switch ( forward_type )
{
case FORWARD_TYPE_NONE :
return " none " ;
case FORWARD_TYPE_STEERING :
return " steering " ;
case FORWARD_TYPE_MIRRORING :
return " mirroring " ;
default :
return " unknown " ;
}
}
static const char * session_action_to_string ( enum session_action session_action )
{
switch ( session_action )
{
case SESSION_ACTION_BYPASS :
return " bypass " ;
case SESSION_ACTION_FORWARD :
return " forward " ;
case SESSION_ACTION_BLOCK :
return " block " ;
default :
return " unknown " ;
}
}
2023-02-21 09:58:31 +08:00
const char * session_action_reason_to_string ( enum session_action_reason session_action_reason )
2023-02-06 10:34:23 +08:00
{
switch ( session_action_reason )
{
case ACTION_BYPASS_DUE_DEFAULT :
return " bypass_due_default " ;
case ACTION_BYPASS_DUE_NO_AVAILABLE_SF :
return " bypass_due_no_available_sf " ;
case ACTION_BYPASS_DUE_HEALTH_SF_LIMIT :
return " bypass_due_health_sf_limit " ;
case ACTION_BYPASS_DUE_UNAVAILABLE_ACTION :
return " bypass_due_unavailable_action " ;
case ACTION_BYPASS_DUE_FAILURE_ACTION :
return " bypass_due_failure_action " ;
case ACTION_BYPASS_DUE_INVALID_POLICY :
return " bypass_due_invalid_policy " ;
case ACTION_BLOCK_DUE_UNAVAILABLE_ACTION :
return " block_due_unavailable_action " ;
case ACTION_BLOCK_DUE_FAILURE_ACTION :
return " block_due_failure_action " ;
case ACTION_FORWAED_DUE_SELECTED_AVAILABLE_SF :
return " forward_due_selected_available_sf " ;
default :
return " unknown " ;
}
}
static const char * package_method_to_string ( enum package_method package_method )
{
switch ( package_method )
{
case PACKAGE_METHOD_NONE :
return " none " ;
case PACKAGE_METHOD_LAYER2_SWITCH :
return " layer2_switch " ;
case PACKAGE_METHOD_LAYER3_SWITCH :
return " layer3_switch " ;
case PACKAGE_METHOD_VXLAN_G :
return " vxlan_g " ;
default :
return " unknown " ;
}
}
// {"tags":[{"tag":"device_group","value":"group-xxg-9140"},{"tag":"data_center","value":"center-xxg-9140"}]}
static void parser_device_group ( const char * accept_tags , char * buffer )
{
cJSON * json ;
cJSON * tags ;
cJSON * elem ;
cJSON * item_key ;
cJSON * item_val ;
json = cJSON_Parse ( accept_tags ) ;
if ( json = = NULL )
{
LOG_ERROR ( " %s: unexpected maat config: (invalid accept_tags format) %s " , LOG_TAG_POLICY , accept_tags ) ;
goto error_out ;
}
tags = cJSON_GetObjectItem ( json , " tags " ) ;
if ( ! tags | | ! cJSON_IsArray ( tags ) | | ! cJSON_GetArraySize ( tags ) )
{
LOG_ERROR ( " %s: unexpected maat config: (invalid accept_tags->tags format) %s " , LOG_TAG_POLICY , accept_tags ) ;
goto error_out ;
}
cJSON_ArrayForEach ( elem , tags )
{
item_key = cJSON_GetObjectItem ( elem , " tag " ) ;
if ( ! item_key | | ! cJSON_IsString ( item_key ) )
{
LOG_ERROR ( " %s: unexpected maat config: (invalid accept_tags->tags->tag format) %s " , LOG_TAG_POLICY , accept_tags ) ;
continue ;
}
item_val = cJSON_GetObjectItem ( elem , " value " ) ;
if ( ! item_val | | ! cJSON_IsString ( item_val ) )
{
LOG_ERROR ( " %s: unexpected maat config: (invalid accept_tags->tags->value format) %s " , LOG_TAG_POLICY , accept_tags ) ;
continue ;
}
if ( strcasecmp ( item_key - > valuestring , " device_group " ) = = 0 )
{
memcpy ( buffer , item_val - > valuestring , strlen ( item_val - > valuestring ) ) ;
break ;
}
}
error_out :
if ( json )
{
cJSON_Delete ( json ) ;
json = NULL ;
}
}
static void policy_enforcer_config ( const char * profile , struct policy_config * config )
{
MESA_load_profile_int_def ( profile , " MAAT " , " input_mode " , ( int * ) & ( config - > input_mode ) , MAAT_INPUT_REDIS ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " stat_switch " , & ( config - > stat_switch ) , 1 ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " perf_switch " , & ( config - > perf_switch ) , 1 ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " scan_detail " , & ( config - > scan_detail ) , 0 ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " deferred_load " , & ( config - > deferred_load ) , 0 ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " effect_interval_ms " , & ( config - > effect_interval_ms ) , 1000 ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " stat_file " , config - > stat_file , sizeof ( config - > stat_file ) , " log/sce.fs2 " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " table_info " , config - > table_info , sizeof ( config - > table_info ) , " resource/table_info.conf " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " accept_path " , config - > accept_path , sizeof ( config - > accept_path ) , " /opt/tsg/etc/tsg_device_tag.json " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " inc_cfg_dir " , config - > inc_cfg_dir , sizeof ( config - > inc_cfg_dir ) , " resource/inc/ " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " ful_cfg_dir " , config - > ful_cfg_dir , sizeof ( config - > ful_cfg_dir ) , " resource/ful/ " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " json_cfg_file " , config - > json_cfg_file , sizeof ( config - > json_cfg_file ) , " resource/sce.json " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " foreign_cont_dir " , config - > foreign_cont_dir , sizeof ( config - > foreign_cont_dir ) , " resource/sce_files " ) ;
MESA_load_profile_int_def ( profile , " MAAT " , " redis_db_idx " , & ( config - > redis_db_idx ) , 0 ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " redis_server " , config - > redis_server , sizeof ( config - > redis_server ) , " 127.0.0.1 " ) ;
MESA_load_profile_string_def ( profile , " MAAT " , " redis_port_range " , config - > redis_port_range , sizeof ( config - > redis_server ) , " 6379 " ) ;
if ( strlen ( config - > accept_path ) )
{
MESA_load_profile_string_def ( config - > accept_path , " MAAT " , " accept_tags " , config - > accept_tags , sizeof ( config - > accept_tags ) , " { \" tags \" :[{ \" tag \" : \" device_id \" , \" value \" : \" device_1 \" }]} " ) ;
parser_device_group ( config - > accept_tags , config - > device_group ) ;
}
LOG_DEBUG ( " %s: MAAT->input_mode : %s " , LOG_TAG_POLICY , ( config - > input_mode = = MAAT_INPUT_REDIS ? " redis " : ( config - > input_mode = = MAAT_INPUT_JSON ? " json " : ( config - > input_mode = = MAAT_INPUT_FILE ? " file " : " unknown " ) ) ) ) ;
LOG_DEBUG ( " %s: MAAT->stat_switch : %d " , LOG_TAG_POLICY , config - > stat_switch ) ;
LOG_DEBUG ( " %s: MAAT->perf_switch : %d " , LOG_TAG_POLICY , config - > perf_switch ) ;
LOG_DEBUG ( " %s: MAAT->scan_detail : %d " , LOG_TAG_POLICY , config - > scan_detail ) ;
LOG_DEBUG ( " %s: MAAT->deferred_load : %d " , LOG_TAG_POLICY , config - > deferred_load ) ;
LOG_DEBUG ( " %s: MAAT->effect_interval_ms : %d " , LOG_TAG_POLICY , config - > effect_interval_ms ) ;
LOG_DEBUG ( " %s: MAAT->stat_file : %s " , LOG_TAG_POLICY , config - > stat_file ) ;
LOG_DEBUG ( " %s: MAAT->table_info : %s " , LOG_TAG_POLICY , config - > table_info ) ;
LOG_DEBUG ( " %s: MAAT->accept_path : %s " , LOG_TAG_POLICY , config - > accept_path ) ;
LOG_DEBUG ( " %s: MAAT->accept_tags : %s " , LOG_TAG_POLICY , config - > accept_tags ) ;
LOG_DEBUG ( " %s: MAAT->device_group : %s " , LOG_TAG_POLICY , config - > device_group ) ;
LOG_DEBUG ( " %s: MAAT->inc_cfg_dir : %s " , LOG_TAG_POLICY , config - > inc_cfg_dir ) ;
LOG_DEBUG ( " %s: MAAT->ful_cfg_dir : %s " , LOG_TAG_POLICY , config - > ful_cfg_dir ) ;
LOG_DEBUG ( " %s: MAAT->json_cfg_file : %s " , LOG_TAG_POLICY , config - > json_cfg_file ) ;
LOG_DEBUG ( " %s: MAAT->foreign_cont_dir : %s " , LOG_TAG_POLICY , config - > foreign_cont_dir ) ;
LOG_DEBUG ( " %s: MAAT->redis_db_idx : %d " , LOG_TAG_POLICY , config - > redis_db_idx ) ;
LOG_DEBUG ( " %s: MAAT->redis_server : %s " , LOG_TAG_POLICY , config - > redis_server ) ;
LOG_DEBUG ( " %s: MAAT->redis_port_range : %s " , LOG_TAG_POLICY , config - > redis_port_range ) ;
}
static void chaining_param_new_cb ( int table_id , const char * key , const char * table_line , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
int iter = 0 ;
cJSON * json = NULL ;
cJSON * item = NULL ;
cJSON * element = NULL ;
size_t user_region_offset = 0 ;
size_t user_region_len = 0 ;
struct chaining_param * param = NULL ;
if ( Maat_helper_read_column ( table_line , 7 , & user_region_offset , & user_region_len ) < 0 )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid user region) %s " , LOG_TAG_POLICY , table_line ) ;
return ;
}
char * json_str = ( char * ) calloc ( user_region_len + 1 , sizeof ( char ) ) ;
memcpy ( json_str , table_line + user_region_offset , user_region_len ) ;
json = cJSON_Parse ( json_str ) ;
if ( json = = NULL )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid json format) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param = ( struct chaining_param * ) calloc ( 1 , sizeof ( struct chaining_param ) ) ;
param - > policy_id = atoi ( key ) ;
param - > ref_cnt = 1 ;
// targeted_traffic
item = cJSON_GetObjectItem ( json , " targeted_traffic " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid targeted_traffic param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
if ( strcasecmp ( item - > valuestring , " raw " ) = = 0 )
{
LOG_DEBUG ( " %s: parse chaining policy: %d, targeted_traffic: raw " , LOG_TAG_POLICY , param - > policy_id ) ;
param - > traffic_type = TRAFFIC_TYPE_RAW ;
}
else if ( strcasecmp ( item - > valuestring , " decrypted " ) = = 0 )
{
LOG_DEBUG ( " %s: parse chaining policy: %d, targeted_traffic: decrypted " , LOG_TAG_POLICY , param - > policy_id ) ;
param - > traffic_type = TRAFFIC_TYPE_DECRYPTED ;
}
else
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid targeted_traffic param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
// sff_profiles
item = cJSON_GetObjectItem ( json , " sff_profiles " ) ;
if ( ! item | | ! cJSON_IsArray ( item ) | | ! cJSON_GetArraySize ( item ) )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid sff_profiles param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sff_profile_ids_num = cJSON_GetArraySize ( item ) ;
param - > sff_profile_ids = ( int * ) calloc ( param - > sff_profile_ids_num , sizeof ( int ) ) ;
cJSON_ArrayForEach ( element , item )
{
if ( ! cJSON_IsNumber ( element ) )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid sff_profiles param) %s " , LOG_TAG_POLICY , table_line ) ;
continue ;
}
LOG_DEBUG ( " %s: parse chaining policy: %d, sff_profiles[%d/%d]: %d " , LOG_TAG_POLICY , param - > policy_id , iter , param - > sff_profile_ids_num , element - > valueint ) ;
param - > sff_profile_ids [ iter ] = element - > valueint ;
iter + + ;
}
* ad = param ;
LOG_INFO ( " %s: Add chaining policy: %d " , LOG_TAG_POLICY , param - > policy_id ) ;
cJSON_Delete ( json ) ;
free ( json_str ) ;
return ;
error_out :
if ( json )
{
cJSON_Delete ( json ) ;
json = NULL ;
}
if ( json_str )
{
free ( json_str ) ;
json_str = NULL ;
}
if ( param )
{
if ( param - > sff_profile_ids )
{
free ( param - > sff_profile_ids ) ;
param - > sff_profile_ids = NULL ;
}
free ( param ) ;
param = NULL ;
}
}
static void chaining_param_free_cb ( int table_id , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
struct chaining_param * param = ( struct chaining_param * ) * ad ;
if ( param = = NULL )
{
return ;
}
if ( ( __sync_sub_and_fetch ( & param - > ref_cnt , 1 ) = = 0 ) )
{
LOG_INFO ( " %s: Del chaining policy: %d " , LOG_TAG_POLICY , param - > policy_id ) ;
if ( param - > sff_profile_ids )
{
free ( param - > sff_profile_ids ) ;
param - > sff_profile_ids = NULL ;
}
free ( param ) ;
param = NULL ;
* ad = NULL ;
}
}
static void chaining_param_dup_cb ( int table_id , MAAT_PLUGIN_EX_DATA * to , MAAT_PLUGIN_EX_DATA * from , long argl , void * argp )
{
struct chaining_param * param = ( struct chaining_param * ) * from ;
if ( param )
{
__sync_add_and_fetch ( & ( param - > ref_cnt ) , 1 ) ;
* to = param ;
}
else
{
* to = NULL ;
}
}
static void chaining_param_free ( struct chaining_param * param )
{
chaining_param_free_cb ( 0 , ( void * * ) & param , 0 , NULL ) ;
}
static void sff_param_new_cb ( int table_id , const char * key , const char * table_line , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
int iter = 0 ;
struct sff_param * param = NULL ;
cJSON * root1 = NULL ;
cJSON * root2 = NULL ;
cJSON * item = NULL ;
int profile_id = 0 ;
int type = 0 ;
char load_balance_method [ 32 ] = { 0 } ;
char load_balance_localization [ 8 ] = { 0 } ;
char failure_action [ 16 ] = { 0 } ;
char unavailability_action [ 64 ] = { 0 } ;
char service_func_profiles [ 128 ] = { 0 } ;
int is_valid = 0 ;
if ( sscanf ( table_line , " %d \t %d \t %s \t %s \t %s \t %s \t %s \t %d " ,
& profile_id , & type ,
load_balance_method , load_balance_localization , failure_action , unavailability_action , service_func_profiles ,
& is_valid ) ! = 8 )
{
LOG_ERROR ( " %s: unexpected sff profile: %s " , LOG_TAG_POLICY , table_line ) ;
return ;
}
param = ( struct sff_param * ) calloc ( 1 , sizeof ( struct sff_param ) ) ;
param - > sff_profile_id = atoi ( key ) ;
param - > sff_ref_cnt = 1 ;
// type
switch ( type )
{
case 1 :
param - > sff_forward_type = FORWARD_TYPE_STEERING ;
LOG_DEBUG ( " %s: parse sff profile: %d, type: steering " , LOG_TAG_POLICY , param - > sff_profile_id ) ;
break ;
case 2 :
param - > sff_forward_type = FORWARD_TYPE_MIRRORING ;
LOG_DEBUG ( " %s: parse sff profile: %d, type: mirroring " , LOG_TAG_POLICY , param - > sff_profile_id ) ;
break ;
default :
LOG_ERROR ( " %s: unexpected sff profile: (invalid type param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
// load_balance_method
if ( 0 = = strcasecmp ( load_balance_method , " hash-int-ip " ) )
{
param - > sff_ldbc . method = LDBC_METHOD_HASH_INT_IP ;
}
else if ( 0 = = strcasecmp ( load_balance_method , " hash-ext-ip " ) )
{
param - > sff_ldbc . method = LDBC_METHOD_HASH_EXT_IP ;
}
else if ( 0 = = strcasecmp ( load_balance_method , " hash-int-ip-and-ext-ip " ) )
{
param - > sff_ldbc . method = LDBC_METHOD_HASH_INT_IP_AND_EXT_IP ;
}
else if ( 0 = = strcasecmp ( load_balance_method , " hash-innermost-int-ip " ) )
{
param - > sff_ldbc . method = LDBC_METHOD_HASH_INNERMOST_INT_IP ;
}
else
{
// not support LDBC_METHOD_HASH_INNERMOST_EXT_IP
LOG_ERROR ( " %s: unexpected sff profile: (invalid load_balance_method param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sff profile: %d, load_balance_method: %s " , LOG_TAG_POLICY , param - > sff_profile_id , load_balance_method ) ;
// load_balance_localization
if ( 0 = = strcasecmp ( load_balance_localization , " nearby " ) )
{
param - > sff_ldbc . localiza = LDBC_LOCALIZATION_NEARBY ;
}
else if ( 0 = = strcasecmp ( load_balance_localization , " global " ) )
{
param - > sff_ldbc . localiza = LDBC_LOCALIZATION_GLOBAL ;
}
else
{
LOG_ERROR ( " %s: unexpected sff profile: (invalid load_balance_localization param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sff profile: %d, load_balance_localization: %s " , LOG_TAG_POLICY , param - > sff_profile_id , load_balance_localization ) ;
// failure_action
if ( 0 = = strcasecmp ( failure_action , " bypass " ) )
{
param - > sff_exception . fail_action = FAILURE_ACTION_BYPASS ;
}
else if ( 0 = = strcasecmp ( failure_action , " block " ) )
{
param - > sff_exception . fail_action = FAILURE_ACTION_BLOCK ;
}
else if ( 0 = = strcasecmp ( failure_action , " re-dispatch " ) )
{
param - > sff_exception . fail_action = FAILURE_ACTION_RE_DISPATCH ;
}
else
{
LOG_ERROR ( " %s: unexpected sff profile: (invalid failure_action param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sff profile: %d, failure_action: %s " , LOG_TAG_POLICY , param - > sff_profile_id , failure_action ) ;
// unavailability_action
if ( param - > sff_exception . fail_action = = FAILURE_ACTION_RE_DISPATCH )
{
root1 = cJSON_Parse ( unavailability_action ) ;
if ( root1 = = NULL )
{
LOG_ERROR ( " %s: unexpected sff profile: (invalid unavailability_action param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
item = cJSON_GetObjectItem ( root1 , " action " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid unavailability_action->action param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
if ( 0 = = strcasecmp ( item - > valuestring , " bypass " ) )
{
param - > sff_exception . unavail_action = UNAVAILABLE_ACTION_BYPASSS ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " block " ) )
{
param - > sff_exception . unavail_action = UNAVAILABLE_ACTION_BLOCK ;
}
else
{
LOG_ERROR ( " %s: unexpected chaining policy: (invalid unavailability_action->action param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sff profile: %d, unavailability_action->action: %s " , LOG_TAG_POLICY , param - > sff_profile_id , item - > valuestring ) ;
item = cJSON_GetObjectItem ( root1 , " health_service_func_lt " ) ;
if ( item & & cJSON_IsNumber ( item ) )
{
param - > sff_exception . health_service_func_lt = item - > valueint ;
LOG_DEBUG ( " %s: parse sff profile: %d, unavailability_action->health_service_func_lt: %d " , LOG_TAG_POLICY , param - > sff_profile_id , item - > valueint ) ;
}
}
// service_func_profiles
root2 = cJSON_Parse ( service_func_profiles ) ;
if ( root2 = = NULL | | ! cJSON_IsArray ( root2 ) | | ! cJSON_GetArraySize ( root2 ) )
{
LOG_ERROR ( " %s: unexpected sff profile: (invalid service_func_profiles param) %s " , LOG_TAG_POLICY , table_line ) ;
return ;
}
param - > sf_profile_ids_num = cJSON_GetArraySize ( root2 ) ;
param - > sf_profile_ids = ( int * ) calloc ( param - > sf_profile_ids_num , sizeof ( int ) ) ;
cJSON_ArrayForEach ( item , root2 )
{
if ( ! cJSON_IsNumber ( item ) )
{
LOG_ERROR ( " %s: unexpected sff profile: (invalid service_func_profiles param) %s " , LOG_TAG_POLICY , table_line ) ;
continue ;
}
LOG_DEBUG ( " %s: parse sff profile: %d, service_func_profiles[%d/%d] = %d " , LOG_TAG_POLICY , param - > sff_profile_id , iter , param - > sf_profile_ids_num , item - > valueint ) ;
param - > sf_profile_ids [ iter ] = item - > valueint ;
iter + + ;
}
* ad = param ;
LOG_INFO ( " %s: Add sff profile: %d " , LOG_TAG_POLICY , param - > sff_profile_id ) ;
cJSON_Delete ( root1 ) ;
cJSON_Delete ( root2 ) ;
return ;
error_out :
if ( root1 )
{
cJSON_Delete ( root1 ) ;
root1 = NULL ;
}
if ( root2 )
{
cJSON_Delete ( root2 ) ;
root2 = NULL ;
}
if ( param )
{
if ( param - > sf_profile_ids )
{
free ( param - > sf_profile_ids ) ;
param - > sf_profile_ids = NULL ;
}
free ( param ) ;
param = NULL ;
}
}
static void sff_param_free_cb ( int table_id , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
struct sff_param * param = ( struct sff_param * ) * ad ;
if ( param = = NULL )
{
return ;
}
if ( ( __sync_sub_and_fetch ( & param - > sff_ref_cnt , 1 ) = = 0 ) )
{
LOG_INFO ( " %s: Del sff profile: %d " , LOG_TAG_POLICY , param - > sff_profile_id ) ;
if ( param - > sf_profile_ids )
{
free ( param - > sf_profile_ids ) ;
param - > sf_profile_ids = NULL ;
}
free ( param ) ;
param = NULL ;
* ad = NULL ;
}
}
static void sff_param_dup_cb ( int table_id , MAAT_PLUGIN_EX_DATA * to , MAAT_PLUGIN_EX_DATA * from , long argl , void * argp )
{
struct sff_param * param = ( struct sff_param * ) * from ;
if ( param )
{
__sync_add_and_fetch ( & ( param - > sff_ref_cnt ) , 1 ) ;
* to = param ;
}
else
{
* to = NULL ;
}
}
static void sff_param_free ( struct sff_param * param )
{
sff_param_free_cb ( 0 , ( void * * ) & param , 0 , NULL ) ;
}
static void sf_param_new_cb ( int table_id , const char * key , const char * table_line , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
struct sf_param * param = NULL ;
cJSON * root1 = NULL ;
cJSON * root2 = NULL ;
cJSON * item = NULL ;
int profile_id = 0 ;
char device_group [ 32 ] = { 0 } ;
int admin_status = 0 ;
char connectivity [ 128 ] = { 0 } ;
char health_check [ 128 ] = { 0 } ;
int is_valid = 0 ;
if ( sscanf ( table_line , " %d \t %s \t %d \t %s \t %s \t %d " ,
& profile_id , device_group , & admin_status , connectivity , health_check , & is_valid ) ! = 6 )
{
LOG_ERROR ( " %s: unexpected sf profile: %s " , LOG_TAG_POLICY , table_line ) ;
return ;
}
param = ( struct sf_param * ) calloc ( 1 , sizeof ( struct sf_param ) ) ;
param - > sf_profile_id = atoi ( key ) ;
param - > sf_ref_cnt = 1 ;
memcpy ( param - > sf_device_group , device_group , strlen ( device_group ) ) ;
// admin_status
switch ( admin_status )
{
case 1 :
param - > sf_admin_status = ADMMIN_STATUS_ACTIVE ;
LOG_DEBUG ( " %s: parse sf profile: %d, admin_status: active " , LOG_TAG_POLICY , param - > sf_profile_id ) ;
break ;
case 0 :
param - > sf_admin_status = ADMMIN_STATUS_INACTIVE ;
LOG_DEBUG ( " %s: parse sf profile: %d, admin_status: inactive " , LOG_TAG_POLICY , param - > sf_profile_id ) ;
break ;
default :
LOG_ERROR ( " %s: unexpected sf profile: (invalid admin_status param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
// connectivity
root1 = cJSON_Parse ( connectivity ) ;
if ( root1 = = NULL )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
item = cJSON_GetObjectItem ( root1 , " method " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity->method param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
if ( 0 = = strcasecmp ( item - > valuestring , " layer2_switch " ) )
{
param - > sf_connectivity . method = PACKAGE_METHOD_LAYER2_SWITCH ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " layer3_switch " ) )
{
param - > sf_connectivity . method = PACKAGE_METHOD_LAYER3_SWITCH ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " vxlan_g " ) )
{
param - > sf_connectivity . method = PACKAGE_METHOD_VXLAN_G ;
}
else
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity->method param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sf profile: %d, connectivity->method: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
if ( param - > sf_connectivity . method = = PACKAGE_METHOD_LAYER2_SWITCH | | param - > sf_connectivity . method = = PACKAGE_METHOD_LAYER3_SWITCH )
{
item = cJSON_GetObjectItem ( root1 , " int_vlan_tag " ) ;
if ( ! item | | ! cJSON_IsNumber ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity->int_vlan_tag param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sf_connectivity . int_vlan_tag = item - > valueint ;
LOG_DEBUG ( " %s: parse sf profile: %d, connectivity->int_vlan_tag: %d " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valueint ) ;
item = cJSON_GetObjectItem ( root1 , " ext_vlan_tag " ) ;
if ( ! item | | ! cJSON_IsNumber ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity->ext_vlan_tag param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sf_connectivity . ext_vlan_tag = item - > valueint ;
LOG_DEBUG ( " %s: parse sf profile: %d, connectivity->ext_vlan_tag: %d " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valueint ) ;
}
else if ( param - > sf_connectivity . method = = PACKAGE_METHOD_VXLAN_G )
{
item = cJSON_GetObjectItem ( root1 , " dest_ip " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid connectivity->dest_ip param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
memcpy ( param - > sf_connectivity . dest_ip , item - > valuestring , strlen ( item - > valuestring ) ) ;
LOG_DEBUG ( " %s: parse sf profile: %d, connectivity->dest_ip: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
2023-02-21 09:58:31 +08:00
// CM does not send this field, but only reads it from json, which is used for debugging
item = cJSON_GetObjectItem ( root1 , " dest_mac " ) ;
if ( item & & cJSON_IsString ( item ) )
{
memcpy ( param - > sf_connectivity . dest_mac , item - > valuestring , strlen ( item - > valuestring ) ) ;
LOG_DEBUG ( " %s: parse sf profile: %d, connectivity->dst_mac: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
}
2023-02-06 10:34:23 +08:00
}
// health_check
root2 = cJSON_Parse ( health_check ) ;
if ( root2 = = NULL )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
item = cJSON_GetObjectItem ( root2 , " method " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->method param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
if ( 0 = = strcasecmp ( item - > valuestring , " none " ) )
{
param - > sf_health_check . method = HEALTH_CHECK_METHOD_NONE ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " in_band_bfd " ) )
{
param - > sf_health_check . method = HEALTH_CHECK_METHOD_IN_BAND_BFD ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " bfd " ) )
{
param - > sf_health_check . method = HEALTH_CHECK_METHOD_BFD ;
}
else if ( 0 = = strcasecmp ( item - > valuestring , " http " ) )
{
param - > sf_health_check . method = HEALTH_CHECK_METHOD_HTTP ;
}
else
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->method param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->method: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
if ( param - > sf_health_check . method = = HEALTH_CHECK_METHOD_BFD | | param - > sf_health_check . method = = HEALTH_CHECK_METHOD_IN_BAND_BFD )
{
item = cJSON_GetObjectItem ( root2 , " address " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->address param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
memcpy ( param - > sf_health_check . address , item - > valuestring , strlen ( item - > valuestring ) ) ;
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->address: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
item = cJSON_GetObjectItem ( root2 , " port " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->port param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sf_health_check . port = atoi ( item - > valuestring ) ;
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->port: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
}
if ( param - > sf_health_check . method = = HEALTH_CHECK_METHOD_HTTP )
{
item = cJSON_GetObjectItem ( root2 , " url " ) ;
if ( ! item | | ! cJSON_IsString ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->url param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
memcpy ( param - > sf_health_check . url , item - > valuestring , strlen ( item - > valuestring ) ) ;
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->url: %s " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valuestring ) ;
}
if ( param - > sf_health_check . method = = HEALTH_CHECK_METHOD_HTTP | | param - > sf_health_check . method = = HEALTH_CHECK_METHOD_BFD | | param - > sf_health_check . method = = HEALTH_CHECK_METHOD_IN_BAND_BFD )
{
item = cJSON_GetObjectItem ( root2 , " interval_ms " ) ;
if ( ! item | | ! cJSON_IsNumber ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->interval_ms param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sf_health_check . interval_ms = item - > valueint ;
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->interval_ms: %d " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valueint ) ;
item = cJSON_GetObjectItem ( root2 , " retires " ) ;
if ( ! item | | ! cJSON_IsNumber ( item ) )
{
LOG_ERROR ( " %s: unexpected sf profile: (invalid health_check->retires param) %s " , LOG_TAG_POLICY , table_line ) ;
goto error_out ;
}
param - > sf_health_check . retires = item - > valueint ;
LOG_DEBUG ( " %s: parse sf profile: %d, health_check->retires: %d " , LOG_TAG_POLICY , param - > sf_profile_id , item - > valueint ) ;
}
health_check_session_add ( param - > sf_profile_id , & param - > sf_health_check ) ;
* ad = param ;
LOG_INFO ( " %s: Add sf profile: %d " , LOG_TAG_POLICY , param - > sf_profile_id ) ;
cJSON_Delete ( root1 ) ;
cJSON_Delete ( root2 ) ;
return ;
error_out :
if ( root1 )
{
cJSON_Delete ( root1 ) ;
root1 = NULL ;
}
if ( root2 )
{
cJSON_Delete ( root2 ) ;
root2 = NULL ;
}
if ( param )
{
free ( param ) ;
param = NULL ;
}
}
static void sf_param_free_cb ( int table_id , MAAT_PLUGIN_EX_DATA * ad , long argl , void * argp )
{
struct sf_param * param = ( struct sf_param * ) * ad ;
if ( param = = NULL )
{
return ;
}
if ( ( __sync_sub_and_fetch ( & param - > sf_ref_cnt , 1 ) = = 0 ) )
{
health_check_session_del ( param - > sf_profile_id ) ;
LOG_INFO ( " %s: Del sf profile: %d " , LOG_TAG_POLICY , param - > sf_profile_id ) ;
free ( param ) ;
param = NULL ;
* ad = NULL ;
}
}
static void sf_param_dup_cb ( int table_id , MAAT_PLUGIN_EX_DATA * to , MAAT_PLUGIN_EX_DATA * from , long argl , void * argp )
{
struct sf_param * param = ( struct sf_param * ) * from ;
if ( param )
{
__sync_add_and_fetch ( & ( param - > sf_ref_cnt ) , 1 ) ;
* to = param ;
}
else
{
* to = NULL ;
}
}
static void sf_param_free ( struct sf_param * param )
{
sf_param_free_cb ( 0 , ( void * * ) & param , 0 , NULL ) ;
}
// After return must check array elem nums
static void select_sf_by_nearby_and_active ( struct policy_enforcer * enforcer , struct sff_param * sff_param , struct fixed_num_array * array )
{
char buffer [ 16 ] ;
struct sf_param * sf = NULL ;
for ( int i = 0 ; i < sff_param - > sf_profile_ids_num ; i + + )
{
memset ( & buffer , 0 , sizeof ( buffer ) ) ;
snprintf ( buffer , sizeof ( buffer ) , " %u " , sff_param - > sf_profile_ids [ i ] ) ;
sf = ( struct sf_param * ) Maat_plugin_get_EX_data ( enforcer - > maat , enforcer - > sf_table_id , buffer ) ;
if ( sf = = NULL )
{
LOG_ERROR ( " %s: failed to get sf parameter of profile %d " , LOG_TAG_POLICY , sff_param - > sf_profile_ids [ i ] ) ;
continue ;
}
if ( sff_param - > sff_ldbc . localiza = = LDBC_LOCALIZATION_NEARBY )
{
if ( strcasecmp ( enforcer - > config . device_group , sf - > sf_device_group ) = = 0 )
{
if ( sf - > sf_admin_status = = ADMMIN_STATUS_ACTIVE )
{
fixed_num_array_add_elem ( array , sff_param - > sf_profile_ids [ i ] ) ;
}
}
}
else
{
if ( sf - > sf_admin_status = = ADMMIN_STATUS_ACTIVE )
{
fixed_num_array_add_elem ( array , sff_param - > sf_profile_ids [ i ] ) ;
}
}
sf_param_free ( sf ) ;
}
}
// return : SESSION_ACTION_BYPASS, not care selected_sf_profile_id
// return : SESSION_ACTION_BLOCK, not care selected_sf_profile_id
// return : SESSION_ACTION_FORWARD, care selected_sf_profile_id
static enum session_action select_sf_by_ldbc ( uint64_t hash , struct sff_param * sff_param , struct fixed_num_array * array , int * selected_sf_profile_id , enum session_action_reason * sf_action_reason )
{
* selected_sf_profile_id = - 1 ;
int sf_is_active = 0 ;
int sf_profile_id = 0 ;
int sf_profile_index = 0 ;
int sf_profile_num = 0 ;
sf_profile_num = fixed_num_array_count_elem ( array ) ;
while ( sf_profile_num )
{
sf_profile_index = ( int ) ( hash % sf_profile_num ) ;
sf_profile_id = fixed_num_array_index_elem ( array , sf_profile_index ) ;
sf_is_active = health_check_session_get_status ( sf_profile_id ) ;
if ( sf_is_active )
{
* selected_sf_profile_id = sf_profile_id ;
* sf_action_reason = ACTION_FORWAED_DUE_SELECTED_AVAILABLE_SF ;
return SESSION_ACTION_FORWARD ;
}
else
{
if ( sff_param - > sff_exception . fail_action = = FAILURE_ACTION_RE_DISPATCH )
{
fixed_num_array_del_elem ( array , sf_profile_id ) ;
sf_profile_num = fixed_num_array_count_elem ( array ) ;
if ( sff_param - > sff_exception . health_service_func_lt > 0 & & sf_profile_num < sff_param - > sff_exception . health_service_func_lt )
{
* sf_action_reason = ACTION_BYPASS_DUE_HEALTH_SF_LIMIT ;
return SESSION_ACTION_BYPASS ;
}
else
{
if ( sf_profile_num = = 0 )
{
if ( sff_param - > sff_exception . unavail_action = = UNAVAILABLE_ACTION_BYPASSS )
{
* sf_action_reason = ACTION_BYPASS_DUE_UNAVAILABLE_ACTION ;
return SESSION_ACTION_BYPASS ;
}
else
{
* sf_action_reason = ACTION_BLOCK_DUE_UNAVAILABLE_ACTION ;
return SESSION_ACTION_BLOCK ;
}
}
else
{
continue ;
}
}
}
else if ( sff_param - > sff_exception . fail_action = = FAILURE_ACTION_BYPASS )
{
* selected_sf_profile_id = sf_profile_id ;
* sf_action_reason = ACTION_BYPASS_DUE_FAILURE_ACTION ;
return SESSION_ACTION_BYPASS ;
}
else if ( sff_param - > sff_exception . fail_action = = FAILURE_ACTION_BLOCK )
{
* selected_sf_profile_id = sf_profile_id ;
* sf_action_reason = ACTION_BLOCK_DUE_FAILURE_ACTION ;
return SESSION_ACTION_BLOCK ;
}
}
} ;
* sf_action_reason = ACTION_BYPASS_DUE_NO_AVAILABLE_SF ;
return SESSION_ACTION_BYPASS ;
}
2023-02-10 14:22:40 +08:00
static void selected_sf_init ( struct selected_sf * item )
{
if ( item )
{
2023-02-21 09:58:31 +08:00
memset ( item , 0 , sizeof ( struct selected_sf ) ) ;
2023-02-10 14:22:40 +08:00
item - > policy_id = - 1 ;
item - > traffic_type = TRAFFIC_TYPE_NONE ;
item - > sff_profile_id = - 1 ;
item - > sff_forward_type = FORWARD_TYPE_NONE ;
item - > sf_need_skip = 0 ;
item - > sf_profile_id = - 1 ;
item - > sf_action = SESSION_ACTION_BYPASS ;
item - > sf_action_reason = ACTION_BYPASS_DUE_DEFAULT ;
}
}
2023-02-06 10:34:23 +08:00
/******************************************************************************
* Public API
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// return NULL : error
// return !NULL : success
struct policy_enforcer * policy_enforcer_create ( const char * instance , const char * profile , int thread_num , void * logger )
{
int ret = 0 ;
int redis_port_begin = 0 ;
int redis_port_end = 0 ;
int redis_port_select = 0 ;
struct policy_enforcer * enforcer = ( struct policy_enforcer * ) calloc ( 1 , sizeof ( struct policy_enforcer ) ) ;
assert ( enforcer ) ;
policy_enforcer_config ( profile , & ( enforcer - > config ) ) ;
enforcer - > maat = Maat_feather ( thread_num , enforcer - > config . table_info , logger ) ;
if ( enforcer - > maat = = NULL )
{
LOG_ERROR ( " %s: unable create maat feather " , LOG_TAG_POLICY ) ;
goto error_out ;
}
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_INSTANCE_NAME , instance , strlen ( instance ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_FOREIGN_CONT_DIR , enforcer - > config . foreign_cont_dir , strlen ( enforcer - > config . foreign_cont_dir ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_SCAN_DETAIL , & ( enforcer - > config . scan_detail ) , sizeof ( enforcer - > config . scan_detail ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_EFFECT_INVERVAL_MS , & ( enforcer - > config . effect_interval_ms ) , sizeof ( enforcer - > config . effect_interval_ms ) ) ;
switch ( enforcer - > config . input_mode )
{
case MAAT_INPUT_JSON :
if ( ! strlen ( enforcer - > config . json_cfg_file ) )
{
LOG_ERROR ( " %s: invalid json_cfg_file " , LOG_TAG_POLICY ) ;
goto error_out ;
}
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_JSON_FILE_PATH , enforcer - > config . json_cfg_file , strlen ( enforcer - > config . json_cfg_file ) ) ;
break ;
case MAAT_INPUT_REDIS :
if ( ! strlen ( enforcer - > config . redis_server ) )
{
LOG_ERROR ( " %s: invalid redis_server " , LOG_TAG_POLICY ) ;
goto error_out ;
}
ret = sscanf ( enforcer - > config . redis_port_range , " %d-%d " , & redis_port_begin , & redis_port_end ) ;
if ( ret = = 1 )
{
redis_port_select = redis_port_begin ;
}
else if ( ret = = 2 )
{
srand ( time ( NULL ) ) ;
redis_port_select = redis_port_begin + rand ( ) % ( redis_port_end - redis_port_begin ) ;
}
else
{
LOG_ERROR ( " %s: invalid redis_port_range " , LOG_TAG_POLICY ) ;
goto error_out ;
}
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_REDIS_PORT , & redis_port_select , sizeof ( redis_port_select ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_REDIS_IP , enforcer - > config . redis_server , strlen ( enforcer - > config . redis_server ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_REDIS_INDEX , & ( enforcer - > config . redis_db_idx ) , sizeof ( enforcer - > config . redis_db_idx ) ) ;
break ;
case MAAT_INPUT_FILE :
if ( ! strlen ( enforcer - > config . ful_cfg_dir ) )
{
LOG_ERROR ( " %s: invalid ful_cfg_dir " , LOG_TAG_POLICY ) ;
goto error_out ;
}
if ( ! strlen ( enforcer - > config . inc_cfg_dir ) )
{
LOG_ERROR ( " %s: invalid inc_cfg_dir " , LOG_TAG_POLICY ) ;
goto error_out ;
}
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_FULL_CFG_DIR , enforcer - > config . ful_cfg_dir , strlen ( enforcer - > config . ful_cfg_dir ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_INC_CFG_DIR , enforcer - > config . inc_cfg_dir , strlen ( enforcer - > config . inc_cfg_dir ) ) ;
break ;
default :
LOG_ERROR ( " %s: invalid input_mode %d " , LOG_TAG_POLICY , enforcer - > config . input_mode ) ;
goto error_out ;
}
if ( enforcer - > config . stat_switch )
{
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_STAT_FILE_PATH , enforcer - > config . stat_file , strlen ( enforcer - > config . stat_file ) ) ;
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_STAT_ON , NULL , 0 ) ;
if ( enforcer - > config . perf_switch )
{
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_PERF_ON , NULL , 0 ) ;
}
}
if ( enforcer - > config . deferred_load )
{
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_DEFERRED_LOAD , NULL , 0 ) ;
}
if ( strlen ( enforcer - > config . accept_tags ) )
{
Maat_set_feather_opt ( enforcer - > maat , MAAT_OPT_ACCEPT_TAGS , & ( enforcer - > config . accept_tags ) , sizeof ( enforcer - > config . accept_tags ) ) ;
}
if ( Maat_initiate_feather ( enforcer - > maat ) < 0 )
{
LOG_ERROR ( " %s: maat init feather failed " , LOG_TAG_POLICY ) ;
goto error_out ;
}
return enforcer ;
error_out :
policy_enforcer_destory ( enforcer ) ;
return NULL ;
}
void policy_enforcer_destory ( struct policy_enforcer * enforcer )
{
if ( enforcer )
{
if ( enforcer - > maat )
{
Maat_burn_feather ( enforcer - > maat ) ;
enforcer - > maat = NULL ;
}
free ( enforcer ) ;
enforcer = NULL ;
}
}
// return 0 : success
// return -1 : error
int policy_enforcer_register ( struct policy_enforcer * enforcer )
{
enforcer - > compile_table_id = Maat_table_register ( enforcer - > maat , " SERVICE_CHAINING_COMPILE " ) ;
if ( enforcer - > compile_table_id < 0 )
{
LOG_ERROR ( " %s: register SERVICE_CHAINING_COMPILE table failed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
enforcer - > sff_table_id = Maat_table_register ( enforcer - > maat , " SERVICE_FUNCTION_FORWARDER_PROFILE " ) ;
if ( enforcer - > sff_table_id < 0 )
{
LOG_ERROR ( " %s: register SERVICE_FUNCTION_FORWARDER_PROFILE table ailed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
enforcer - > sf_table_id = Maat_table_register ( enforcer - > maat , " SERVICE_FUNCTION_PROFILE " ) ;
if ( enforcer - > sf_table_id < 0 )
{
LOG_ERROR ( " %s: register SERVICE_FUNCTION_PROFILE table failed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
if ( Maat_plugin_EX_register ( enforcer - > maat , enforcer - > compile_table_id ,
chaining_param_new_cb ,
chaining_param_free_cb ,
chaining_param_dup_cb ,
NULL , 0 , enforcer ) ! = 0 )
{
LOG_ERROR ( " %s: register SERVICE_CHAINING_COMPILE plugin extension callbacks failed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
if ( Maat_plugin_EX_register ( enforcer - > maat , enforcer - > sff_table_id ,
sff_param_new_cb ,
sff_param_free_cb ,
sff_param_dup_cb ,
NULL , 0 , enforcer ) ! = 0 )
{
LOG_ERROR ( " %s: register SERVICE_FUNCTION_FORWARDER_PROFILE plugin extension callbacks failed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
if ( Maat_plugin_EX_register ( enforcer - > maat , enforcer - > sf_table_id ,
sf_param_new_cb ,
sf_param_free_cb ,
sf_param_dup_cb ,
NULL , 0 , enforcer ) ! = 0 )
{
LOG_ERROR ( " %s: register SERVICE_FUNCTION_PROFILE plugin extension callbacks failed " , LOG_TAG_POLICY ) ;
return - 1 ;
}
return 0 ;
}
// return NULL : error
// return !NULL : success
struct selected_chaining * selected_chaining_create ( int chaining_size )
{
struct selected_chaining * chaining = ( struct selected_chaining * ) calloc ( 1 , sizeof ( struct selected_chaining ) ) ;
assert ( chaining ) ;
2023-02-10 14:22:40 +08:00
chaining - > chaining_used = 0 ;
2023-02-06 10:34:23 +08:00
chaining - > chaining_size = chaining_size ;
chaining - > chaining = ( struct selected_sf * ) calloc ( chaining - > chaining_size , sizeof ( struct selected_sf ) ) ;
assert ( chaining - > chaining ) ;
for ( int i = 0 ; i < chaining - > chaining_size ; i + + )
{
2023-02-10 14:22:40 +08:00
struct selected_sf * item = & ( chaining - > chaining [ i ] ) ;
selected_sf_init ( item ) ;
2023-02-06 10:34:23 +08:00
}
return chaining ;
}
void selected_chaining_destory ( struct selected_chaining * chaining )
{
if ( chaining )
{
if ( chaining - > chaining )
{
free ( chaining - > chaining ) ;
chaining - > chaining = NULL ;
}
free ( chaining ) ;
chaining = NULL ;
}
}
void selected_chaining_dump ( struct selected_chaining * chaining )
{
if ( chaining = = NULL )
{
LOG_DEBUG ( " %s: selected_chaining: NULL " , LOG_TAG_POLICY ) ;
return ;
}
LOG_DEBUG ( " %s: selected_chaining->chaining_size : %d " , LOG_TAG_POLICY , chaining - > chaining_size ) ;
2023-02-10 14:22:40 +08:00
LOG_DEBUG ( " %s: selected_chaining->chaining_used : %d " , LOG_TAG_POLICY , chaining - > chaining_used ) ;
2023-02-06 10:34:23 +08:00
2023-02-10 14:22:40 +08:00
for ( int i = 0 ; i < chaining - > chaining_used ; i + + )
2023-02-06 10:34:23 +08:00
{
struct selected_sf * node = & ( chaining - > chaining [ i ] ) ;
2023-02-10 14:22:40 +08:00
LOG_DEBUG ( " %s: selected_chaining->node[%d]->policy_id : %d " , LOG_TAG_POLICY , i , node - > policy_id ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->traffic_type : %s " , LOG_TAG_POLICY , i , traffic_type_to_string ( node - > traffic_type ) ) ;
2023-02-06 10:34:23 +08:00
// sff
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sff_profile_id : %d " , LOG_TAG_POLICY , i , node - > sff_profile_id ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sff_forward_type : %s " , LOG_TAG_POLICY , i , forward_type_to_string ( node - > sff_forward_type ) ) ;
// sf
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_profile_id : %d " , LOG_TAG_POLICY , i , node - > sf_profile_id ) ;
2023-02-10 14:22:40 +08:00
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_need_skip : %d " , LOG_TAG_POLICY , i , node - > sf_need_skip ) ;
2023-02-06 10:34:23 +08:00
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_action : %s " , LOG_TAG_POLICY , i , session_action_to_string ( node - > sf_action ) ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_action_reason : %s " , LOG_TAG_POLICY , i , session_action_reason_to_string ( node - > sf_action_reason ) ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_connectivity->package_method : %s " , LOG_TAG_POLICY , i , package_method_to_string ( node - > sf_connectivity . method ) ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_connectivity->int_vlan_tag : %d " , LOG_TAG_POLICY , i , node - > sf_connectivity . int_vlan_tag ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_connectivity->ext_vlan_tag : %d " , LOG_TAG_POLICY , i , node - > sf_connectivity . ext_vlan_tag ) ;
LOG_DEBUG ( " %s: selected_chaining->node[%d]->sf_connectivity->dest_ip : %s " , LOG_TAG_POLICY , i , node - > sf_connectivity . dest_ip ) ;
}
}
void selected_chaining_bref ( struct selected_chaining * chaining )
{
if ( chaining = = NULL )
{
return ;
}
char buff [ 4096 ] = { 0 } ;
int buff_used = 0 ;
int buff_size = sizeof ( buff ) ;
2023-02-10 14:22:40 +08:00
buff_used + = snprintf ( buff + buff_used , buff_size - buff_used , " chaining_size:%d, chaining_used:%d, { " , chaining - > chaining_size , chaining - > chaining_used ) ;
for ( int i = 0 ; i < chaining - > chaining_used ; i + + )
2023-02-06 10:34:23 +08:00
{
struct selected_sf * node = & ( chaining - > chaining [ i ] ) ;
if ( buff_size - buff_used > 0 )
{
2023-02-10 14:22:40 +08:00
buff_used + = snprintf ( buff + buff_used , buff_size - buff_used , " \" node[%d] \" :{ \" skip \" :%d, \" reason \" : \" %s \" , \" policy_id \" :%d, \" sff_profile_id \" :%d, \" sf_profile_id \" :%d}, " , i , node - > sf_need_skip , session_action_reason_to_string ( node - > sf_action_reason ) , node - > policy_id , node - > sff_profile_id , node - > sf_profile_id ) ;
2023-02-06 10:34:23 +08:00
}
}
2023-02-10 14:22:40 +08:00
LOG_DEBUG ( " %s: selected_chaining_bref: %s} " , LOG_TAG_POLICY , buff ) ;
2023-02-06 10:34:23 +08:00
}
2023-02-10 14:22:40 +08:00
void policy_enforce_select_chaining ( struct selected_chaining * chaining , struct policy_enforcer * enforcer , struct raw_pkt_parser * parser , int policy_id , int dir_is_internal )
2023-02-06 10:34:23 +08:00
{
uint64_t hash_value = 0 ;
char buffer [ 16 ] = { 0 } ;
struct sf_param * sf_param = NULL ;
struct sff_param * sff_param = NULL ;
struct fixed_num_array array = { 0 } ;
struct chaining_param * chaining_param = NULL ;
snprintf ( buffer , sizeof ( buffer ) , " %d " , policy_id ) ;
chaining_param = ( struct chaining_param * ) Maat_plugin_get_EX_data ( enforcer - > maat , enforcer - > compile_table_id , buffer ) ;
if ( chaining_param = = NULL )
{
2023-02-10 14:22:40 +08:00
LOG_ERROR ( " %s: failed to get chaining parameter of policy %d " , LOG_TAG_POLICY , policy_id ) ;
return ;
2023-02-06 10:34:23 +08:00
}
LOG_DEBUG ( " %s: enforce chaining policy %d " , LOG_TAG_POLICY , policy_id ) ;
2023-02-10 14:22:40 +08:00
for ( int i = 0 ; i < chaining_param - > sff_profile_ids_num & & chaining - > chaining_used < chaining - > chaining_size ; i + + )
2023-02-06 10:34:23 +08:00
{
2023-02-10 14:22:40 +08:00
struct selected_sf * item = & ( chaining - > chaining [ chaining - > chaining_used ] ) ;
selected_sf_init ( item ) ;
item - > policy_id = policy_id ;
item - > traffic_type = chaining_param - > traffic_type ;
2023-02-06 10:34:23 +08:00
item - > sff_profile_id = chaining_param - > sff_profile_ids [ i ] ;
2023-02-20 15:30:32 +08:00
item - > sf_index = chaining - > chaining_used ;
2023-02-06 10:34:23 +08:00
memset ( buffer , 0 , sizeof ( buffer ) ) ;
snprintf ( buffer , sizeof ( buffer ) , " %u " , item - > sff_profile_id ) ;
sff_param = ( struct sff_param * ) Maat_plugin_get_EX_data ( enforcer - > maat , enforcer - > sff_table_id , buffer ) ;
if ( sff_param = = NULL )
{
LOG_ERROR ( " %s: failed to get sff parameter of profile %d, bypass current sff !!! " , LOG_TAG_POLICY , item - > sff_profile_id ) ;
item - > sf_action = SESSION_ACTION_BYPASS ;
item - > sf_action_reason = ACTION_BYPASS_DUE_INVALID_POLICY ;
2023-02-10 14:22:40 +08:00
chaining - > chaining_used + + ;
2023-02-06 10:34:23 +08:00
continue ;
}
item - > sff_forward_type = sff_param - > sff_forward_type ;
2023-02-22 19:55:05 +08:00
LOG_DEBUG ( " %s: chaining policy %d -> sff_profile %d sf_profile_ids_num %d (before filter nearby and sctive) " , LOG_TAG_POLICY , policy_id , item - > sff_profile_id , sff_param - > sf_profile_ids_num ) ;
2023-02-06 10:34:23 +08:00
memset ( & array , 0 , sizeof ( array ) ) ;
fixed_num_array_init ( & array ) ;
select_sf_by_nearby_and_active ( enforcer , sff_param , & array ) ;
2023-02-22 19:55:05 +08:00
LOG_DEBUG ( " %s: chaining policy %d -> sff_profile %d sf_profile_ids_num %d (after filter nearby and sctive) " , LOG_TAG_POLICY , policy_id , item - > sff_profile_id , fixed_num_array_count_elem ( & array ) ) ;
2023-02-06 10:34:23 +08:00
if ( fixed_num_array_count_elem ( & array ) = = 0 )
{
LOG_DEBUG ( " %s: chaining policy %d -> sff_profile %d, no sf available after filtering by 'nearby & active', bypass current sff !!! " , LOG_TAG_POLICY , policy_id , item - > sff_profile_id ) ;
item - > sf_action = SESSION_ACTION_BYPASS ;
item - > sf_action_reason = ACTION_BYPASS_DUE_NO_AVAILABLE_SF ;
2023-02-10 14:22:40 +08:00
chaining - > chaining_used + + ;
2023-02-06 10:34:23 +08:00
sff_param_free ( sff_param ) ;
continue ;
}
hash_value = raw_packet_parser_get_hash_value ( parser , sff_param - > sff_ldbc . method , dir_is_internal ) ;
item - > sf_action = select_sf_by_ldbc ( hash_value , sff_param , & array , & ( item - > sf_profile_id ) , & ( item - > sf_action_reason ) ) ;
2023-02-22 19:55:05 +08:00
LOG_DEBUG ( " %s: chaining policy %d -> sff_profile %d sf_profile_ids_num %d (after filter ldbc) " , LOG_TAG_POLICY , policy_id , item - > sff_profile_id , fixed_num_array_count_elem ( & array ) ) ;
2023-02-06 10:34:23 +08:00
if ( item - > sf_action ! = SESSION_ACTION_FORWARD )
{
2023-02-10 14:22:40 +08:00
chaining - > chaining_used + + ;
2023-02-06 10:34:23 +08:00
sff_param_free ( sff_param ) ;
continue ;
}
memset ( & buffer , 0 , sizeof ( buffer ) ) ;
snprintf ( buffer , sizeof ( buffer ) , " %u " , item - > sf_profile_id ) ;
sf_param = ( struct sf_param * ) Maat_plugin_get_EX_data ( enforcer - > maat , enforcer - > sf_table_id , buffer ) ;
if ( sf_param = = NULL )
{
LOG_ERROR ( " %s: failed to get sf parameter of selected profile %d, bypass current sff !!! " , LOG_TAG_POLICY , item - > sf_profile_id ) ;
item - > sf_action = SESSION_ACTION_BYPASS ;
item - > sf_action_reason = ACTION_BYPASS_DUE_INVALID_POLICY ;
2023-02-10 14:22:40 +08:00
chaining - > chaining_used + + ;
2023-02-06 10:34:23 +08:00
sff_param_free ( sff_param ) ;
continue ;
}
item - > sf_connectivity . method = sf_param - > sf_connectivity . method ;
item - > sf_connectivity . int_vlan_tag = sf_param - > sf_connectivity . int_vlan_tag ;
item - > sf_connectivity . ext_vlan_tag = sf_param - > sf_connectivity . ext_vlan_tag ;
memcpy ( item - > sf_connectivity . dest_ip , sf_param - > sf_connectivity . dest_ip , strlen ( sf_param - > sf_connectivity . dest_ip ) ) ;
2023-02-21 09:58:31 +08:00
memcpy ( item - > sf_dst_ip , sf_param - > sf_connectivity . dest_ip , strlen ( sf_param - > sf_connectivity . dest_ip ) ) ;
if ( strlen ( sf_param - > sf_connectivity . dest_mac ) )
{
// CM does not send this field, but only reads it from json, which is used for debugging
memcpy ( item - > sf_dst_mac , sf_param - > sf_connectivity . dest_ip , strlen ( sf_param - > sf_connectivity . dest_ip ) ) ;
}
else
{
health_check_session_get_mac ( item - > sf_profile_id , item - > sf_dst_mac ) ;
}
2023-02-10 14:22:40 +08:00
chaining - > chaining_used + + ;
2023-02-06 10:34:23 +08:00
sf_param_free ( sf_param ) ;
sff_param_free ( sff_param ) ;
}
2023-02-10 14:22:40 +08:00
// Selected Service Chaining Before Unique : [1,2,3,1,2]
// Selected Service Chaining After Unique : [1,2,3]
for ( int i = 0 ; i < chaining - > chaining_used ; i + + )
{
struct selected_sf * node_i = & ( chaining - > chaining [ i ] ) ;
for ( int j = 0 ; j < i ; j + + )
{
struct selected_sf * node_j = & ( chaining - > chaining [ j ] ) ;
if ( node_i - > sf_profile_id = = node_j - > sf_profile_id )
{
node_i - > sf_need_skip = 1 ;
break ;
}
}
}
2023-02-06 10:34:23 +08:00
2023-02-10 14:22:40 +08:00
chaining_param_free ( chaining_param ) ;
2023-02-06 10:34:23 +08:00
}