1709 lines
61 KiB
C++
1709 lines
61 KiB
C++
#include <time.h>
|
|
#include <assert.h>
|
|
#include <arpa/inet.h>
|
|
#include <cjson/cJSON.h>
|
|
#include <MESA/maat.h>
|
|
#include <MESA/MESA_prof_load.h>
|
|
|
|
#include "global_metrics.h"
|
|
#include "health_check.h"
|
|
#include "raw_packet.h"
|
|
#include "policy.h"
|
|
#include "utils.h"
|
|
#include "log.h"
|
|
#include "sce.h"
|
|
|
|
/******************************************************************************
|
|
* Struct policy_enforcer
|
|
******************************************************************************/
|
|
|
|
#define EFFECTIVE_RANGE_MAX_SIZE 128
|
|
|
|
enum input_mode
|
|
{
|
|
MAAT_INPUT_JSON = 0,
|
|
MAAT_INPUT_REDIS = 1,
|
|
MAAT_INPUT_FILE = 2,
|
|
};
|
|
|
|
struct policy_config
|
|
{
|
|
enum input_mode input_mode;
|
|
|
|
int log_level;
|
|
int stat_switch;
|
|
int perf_switch;
|
|
int scan_detail;
|
|
int deferred_load;
|
|
int effect_interval_ms;
|
|
|
|
char data_center[EFFECTIVE_RANGE_MAX_SIZE];
|
|
char device_group[EFFECTIVE_RANGE_MAX_SIZE];
|
|
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];
|
|
int max_chaining_size;
|
|
};
|
|
|
|
struct policy_enforcer
|
|
{
|
|
struct policy_config config;
|
|
struct maat *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
|
|
{
|
|
uint64_t rule_id;
|
|
int ref_cnt;
|
|
int vsys_id;
|
|
|
|
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,
|
|
};
|
|
|
|
enum effective_type
|
|
{
|
|
EFFECTIVE_TYPE_DEVICE_GROUP = 0x1,
|
|
EFFECTIVE_TYPE_DATA_CENTER = 0x2,
|
|
};
|
|
|
|
struct effective_range
|
|
{
|
|
enum effective_type type;
|
|
char value[EFFECTIVE_RANGE_MAX_SIZE];
|
|
};
|
|
|
|
struct sf_param
|
|
{
|
|
int sf_vsys_id;
|
|
int sf_profile_id;
|
|
int sf_ref_cnt;
|
|
|
|
enum admin_status sf_admin_status;
|
|
struct connectivity sf_connectivity;
|
|
struct health_check sf_health_check;
|
|
struct effective_range sf_effective_range;
|
|
|
|
uint64_t health_check_session_id;
|
|
};
|
|
|
|
/******************************************************************************
|
|
* Private API
|
|
******************************************************************************/
|
|
|
|
static const char *effective_type_to_string(enum effective_type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case EFFECTIVE_TYPE_DEVICE_GROUP:
|
|
return "device_group";
|
|
case EFFECTIVE_TYPE_DATA_CENTER:
|
|
return "data_center";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
static const char *admin_status_to_string(enum admin_status admin_status)
|
|
{
|
|
switch (admin_status)
|
|
{
|
|
case ADMMIN_STATUS_ACTIVE:
|
|
return "active";
|
|
case ADMMIN_STATUS_INACTIVE:
|
|
return "inactive";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
// {"tags":[{"tag":"device_group","value":"group-xxg-9140"},{"tag":"data_center","value":"center-xxg-9140"}]}
|
|
static void parser_effective_range(const char *accept_tags, char *data_center, char *device_group)
|
|
{
|
|
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)
|
|
{
|
|
memset(device_group, 0, EFFECTIVE_RANGE_MAX_SIZE);
|
|
memcpy(device_group, item_val->valuestring, MIN(strlen(item_val->valuestring), EFFECTIVE_RANGE_MAX_SIZE));
|
|
}
|
|
|
|
if (strcasecmp(item_key->valuestring, "data_center") == 0)
|
|
{
|
|
memset(data_center, 0, EFFECTIVE_RANGE_MAX_SIZE);
|
|
memcpy(data_center, item_val->valuestring, MIN(strlen(item_val->valuestring), EFFECTIVE_RANGE_MAX_SIZE));
|
|
}
|
|
}
|
|
|
|
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);
|
|
// LOG_LEVEL_TRACE = 0; LOG_LEVEL_DEBUG = 1; LOG_LEVEL_INFO = 2;
|
|
// LOG_LEVEL_WARN = 3; LOG_LEVEL_ERROR = 4; LOG_LEVEL_FATAL = 5;
|
|
MESA_load_profile_int_def(profile, "MAAT", "log_level", &(config->log_level), 5);
|
|
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/maat.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");
|
|
MESA_load_profile_int_def(profile, "MAAT", "max_chaining_size", &(config->max_chaining_size), 32);
|
|
|
|
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_effective_range(config->accept_tags, config->data_center, 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->log_level : %d", LOG_TAG_POLICY, config->log_level);
|
|
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->data_center : %s", LOG_TAG_POLICY, config->data_center);
|
|
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);
|
|
LOG_DEBUG("%s: MAAT->max_chaining_size : %d", LOG_TAG_POLICY, config->max_chaining_size);
|
|
}
|
|
|
|
static void chaining_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **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 rule: (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 rule: (invalid json format) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
|
|
param = (struct chaining_param *)calloc(1, sizeof(struct chaining_param));
|
|
param->rule_id = atoll(key);
|
|
param->ref_cnt = 1;
|
|
|
|
// vsys_id
|
|
item = cJSON_GetObjectItem(json, "vsys_id");
|
|
if (!item || !cJSON_IsNumber(item))
|
|
{
|
|
LOG_ERROR("%s: unexpected chaining rule: (invalid vsys_id param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
param->vsys_id = item->valueint;
|
|
LOG_DEBUG("%s: parse chaining rule: %lu, vsys_id: %d", LOG_TAG_POLICY, param->rule_id, param->vsys_id);
|
|
|
|
// targeted_traffic
|
|
item = cJSON_GetObjectItem(json, "targeted_traffic");
|
|
if (!item || !cJSON_IsString(item))
|
|
{
|
|
LOG_ERROR("%s: unexpected chaining rule: (invalid targeted_traffic param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
if (strcasecmp(item->valuestring, "raw") == 0)
|
|
{
|
|
param->traffic_type = TRAFFIC_TYPE_RAW;
|
|
}
|
|
else if (strcasecmp(item->valuestring, "decrypted") == 0)
|
|
{
|
|
param->traffic_type = TRAFFIC_TYPE_DECRYPTED;
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR("%s: unexpected chaining rule: (invalid targeted_traffic param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
LOG_DEBUG("%s: parse chaining rule: %lu, targeted_traffic: %s", LOG_TAG_POLICY, param->rule_id, traffic_type_to_string(param->traffic_type));
|
|
|
|
// sff_profiles
|
|
item = cJSON_GetObjectItem(json, "sff_profiles");
|
|
if (!item || !cJSON_IsArray(item) || !cJSON_GetArraySize(item))
|
|
{
|
|
LOG_ERROR("%s: unexpected chaining rule: (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 rule: (invalid sff_profiles param) %s", LOG_TAG_POLICY, table_line);
|
|
continue;
|
|
}
|
|
|
|
LOG_DEBUG("%s: parse chaining rule: %lu, sff_profiles[%d/%d]: %d", LOG_TAG_POLICY, param->rule_id, iter, param->sff_profile_ids_num, element->valueint);
|
|
param->sff_profile_ids[iter] = element->valueint;
|
|
iter++;
|
|
}
|
|
|
|
*ad = param;
|
|
LOG_INFO("%s: Add chaining rule: %lu", LOG_TAG_POLICY, param->rule_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, void **ad, long argl, void *argp)
|
|
{
|
|
struct chaining_param *param = (struct chaining_param *)*ad;
|
|
if (param == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0))
|
|
{
|
|
LOG_INFO("%s: Del chaining rule: %lu", LOG_TAG_POLICY, param->rule_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, void **to, void **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 **)¶m, 0, NULL);
|
|
}
|
|
|
|
static void sff_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **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;
|
|
break;
|
|
case 2:
|
|
param->sff_forward_type = FORWARD_TYPE_MIRRORING;
|
|
break;
|
|
default:
|
|
LOG_ERROR("%s: unexpected sff profile: (invalid type param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
LOG_DEBUG("%s: parse sff profile: %d, type: %s", LOG_TAG_POLICY, param->sff_profile_id, forward_type_to_string(param->sff_forward_type));
|
|
|
|
// 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 rule: (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 rule: (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, void **ad, long argl, void *argp)
|
|
{
|
|
struct sff_param *param = (struct sff_param *)*ad;
|
|
if (param == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((__sync_sub_and_fetch(¶m->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, void **to, void **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 **)¶m, 0, NULL);
|
|
}
|
|
|
|
static void sf_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp)
|
|
{
|
|
struct sf_param *param = NULL;
|
|
cJSON *root0 = NULL;
|
|
cJSON *root1 = NULL;
|
|
cJSON *root2 = NULL;
|
|
cJSON *item = NULL;
|
|
|
|
int vsys_id = 0;
|
|
int is_valid = 0;
|
|
int profile_id = 0;
|
|
int admin_status = 0;
|
|
char connectivity[128] = {0};
|
|
char health_check[128] = {0};
|
|
char device_group[EFFECTIVE_RANGE_MAX_SIZE] = {0};
|
|
|
|
if (sscanf(table_line, "%d\t%s\t%d\t%s\t%s\t%d\t%d",
|
|
&profile_id, device_group, &admin_status, connectivity, health_check, &vsys_id, &is_valid) != 7)
|
|
{
|
|
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_vsys_id = vsys_id;
|
|
param->sf_profile_id = atoi(key);
|
|
param->sf_ref_cnt = 1;
|
|
|
|
// device_group
|
|
root0 = cJSON_Parse(device_group);
|
|
if (root0 == NULL)
|
|
{
|
|
LOG_ERROR("%s: unexpected sf profile: (invalid device_group param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
item = cJSON_GetObjectItem(root0, "tag");
|
|
if (!item || !cJSON_IsString(item))
|
|
{
|
|
LOG_ERROR("%s: unexpected sf profile: (invalid device_group->tag param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
if (0 == strcasecmp(item->valuestring, "device_group"))
|
|
{
|
|
param->sf_effective_range.type = EFFECTIVE_TYPE_DEVICE_GROUP;
|
|
}
|
|
else if (0 == strcasecmp(item->valuestring, "data_center"))
|
|
{
|
|
param->sf_effective_range.type = EFFECTIVE_TYPE_DATA_CENTER;
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR("%s: unexpected sf profile: (invalid device_group->tag param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
item = cJSON_GetObjectItem(root0, "value");
|
|
if (!item || !cJSON_IsString(item))
|
|
{
|
|
LOG_ERROR("%s: unexpected sf profile: (invalid device_group->value param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
memcpy(param->sf_effective_range.value, item->valuestring, MIN(strlen(item->valuestring), EFFECTIVE_RANGE_MAX_SIZE));
|
|
LOG_DEBUG("%s: parse sf profile: %d, device_group->tag: %s, device_group->value: %s", LOG_TAG_POLICY, param->sf_profile_id, effective_type_to_string(param->sf_effective_range.type), param->sf_effective_range.value);
|
|
|
|
// admin_status
|
|
switch (admin_status)
|
|
{
|
|
case 1:
|
|
param->sf_admin_status = ADMMIN_STATUS_ACTIVE;
|
|
break;
|
|
case 0:
|
|
param->sf_admin_status = ADMMIN_STATUS_INACTIVE;
|
|
break;
|
|
default:
|
|
LOG_ERROR("%s: unexpected sf profile: (invalid admin_status param) %s", LOG_TAG_POLICY, table_line);
|
|
goto error_out;
|
|
}
|
|
LOG_DEBUG("%s: parse sf profile: %d, admin_status: %s", LOG_TAG_POLICY, param->sf_profile_id, admin_status_to_string(param->sf_admin_status));
|
|
|
|
// 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, package_method_to_string(param->sf_connectivity.method));
|
|
|
|
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);
|
|
}
|
|
|
|
// 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_connectivity.method == PACKAGE_METHOD_VXLAN_G) ||
|
|
(param->sf_health_check.method == HEALTH_CHECK_METHOD_NONE && param->sf_connectivity.method == PACKAGE_METHOD_VXLAN_G))
|
|
{
|
|
memcpy(param->sf_health_check.address, param->sf_connectivity.dest_ip, strlen(param->sf_connectivity.dest_ip));
|
|
}
|
|
|
|
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);
|
|
}
|
|
param->health_check_session_id = health_check_session_add(param->sf_profile_id, param->sf_vsys_id, ¶m->sf_health_check);
|
|
|
|
*ad = param;
|
|
LOG_INFO("%s: Add sf profile: %d", LOG_TAG_POLICY, param->sf_profile_id);
|
|
|
|
cJSON_Delete(root0);
|
|
cJSON_Delete(root1);
|
|
cJSON_Delete(root2);
|
|
return;
|
|
|
|
error_out:
|
|
if (root0)
|
|
{
|
|
cJSON_Delete(root0);
|
|
root0 = NULL;
|
|
}
|
|
|
|
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, void **ad, long argl, void *argp)
|
|
{
|
|
struct sf_param *param = (struct sf_param *)*ad;
|
|
if (param == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((__sync_sub_and_fetch(¶m->sf_ref_cnt, 1) == 0))
|
|
{
|
|
health_check_session_del(param->health_check_session_id, 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, void **to, void **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 **)¶m, 0, NULL);
|
|
}
|
|
|
|
// After return must check array elem nums
|
|
static void select_sf_by_nearby_and_adminstatus(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_table_get_ex_data(enforcer->maat, enforcer->sf_table_id, buffer, strlen(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 (sf->sf_effective_range.type == EFFECTIVE_TYPE_DEVICE_GROUP)
|
|
{
|
|
if (strcasecmp(enforcer->config.device_group, sf->sf_effective_range.value) == 0)
|
|
{
|
|
if (sf->sf_admin_status == ADMMIN_STATUS_ACTIVE)
|
|
{
|
|
fixed_num_array_add_elem(array, sff_param->sf_profile_ids[i]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcasecmp(enforcer->config.data_center, sf->sf_effective_range.value) == 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(struct policy_enforcer *enforcer, struct session_ctx *s_ctx, struct sff_param *sff_param, struct selected_sf *sf, struct fixed_num_array *array, uint64_t hash)
|
|
{
|
|
struct thread_ctx *thread = (struct thread_ctx *)s_ctx->ref_thread_ctx;
|
|
struct global_metrics *g_metrics = thread->ref_metrics;
|
|
struct sf_param *sf_param = NULL;
|
|
char buffer[16];
|
|
|
|
sf->sf_profile_id = -1;
|
|
int sf_profile_id = 0;
|
|
int sf_profile_index = 0;
|
|
int sf_profile_num = 0;
|
|
uint64_t health_check_session_id = 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);
|
|
|
|
memset(&buffer, 0, sizeof(buffer));
|
|
snprintf(buffer, sizeof(buffer), "%u", sf_profile_id);
|
|
sf_param = (struct sf_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->sf_table_id, buffer, strlen(buffer));
|
|
if (sf_param == NULL)
|
|
{
|
|
LOG_ERROR("%s: failed to get sf parameter of profile %d", LOG_TAG_POLICY, sf_profile_id);
|
|
fixed_num_array_del_elem(array, sf_profile_id);
|
|
continue;
|
|
}
|
|
health_check_session_id = sf_param->health_check_session_id;
|
|
sf_param_free(sf_param);
|
|
|
|
memset(sf->sf_dst_mac, 0, sizeof(sf->sf_dst_mac));
|
|
if (health_check_session_get_mac(health_check_session_id, sf->sf_dst_mac) == 0)
|
|
{
|
|
ATOMIC_INC(&(g_metrics->sf_status.active));
|
|
|
|
sf->sf_profile_id = sf_profile_id;
|
|
sf->sf_action_reason = ACTION_FORWAED_DUE_SELECTED_SF;
|
|
return SESSION_ACTION_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
ATOMIC_INC(&(g_metrics->sf_status.inactive));
|
|
|
|
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->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->sf_action_reason = ACTION_BYPASS_DUE_UNAVAILABLE_ACTION;
|
|
return SESSION_ACTION_BYPASS;
|
|
}
|
|
else
|
|
{
|
|
sf->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)
|
|
{
|
|
sf->sf_profile_id = sf_profile_id;
|
|
sf->sf_action_reason = ACTION_BYPASS_DUE_FAILURE_ACTION;
|
|
return SESSION_ACTION_BYPASS;
|
|
}
|
|
else if (sff_param->sff_exception.fail_action == FAILURE_ACTION_BLOCK)
|
|
{
|
|
sf->sf_profile_id = sf_profile_id;
|
|
sf->sf_action_reason = ACTION_BLOCK_DUE_FAILURE_ACTION;
|
|
return SESSION_ACTION_BLOCK;
|
|
}
|
|
}
|
|
};
|
|
|
|
sf->sf_action_reason = ACTION_BYPASS_DUE_INVALID_POLICY;
|
|
return SESSION_ACTION_BYPASS;
|
|
}
|
|
|
|
static void selected_sf_init(struct selected_sf *item)
|
|
{
|
|
if (item)
|
|
{
|
|
memset(item, 0, sizeof(struct selected_sf));
|
|
item->rule_vsys_id = 0;
|
|
item->rule_id = 0;
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void connectivity_copy(struct connectivity *dst, struct connectivity *src)
|
|
{
|
|
if (dst && src)
|
|
{
|
|
dst->method = src->method;
|
|
dst->int_vlan_tag = src->int_vlan_tag;
|
|
dst->ext_vlan_tag = src->ext_vlan_tag;
|
|
memcpy(dst->dest_ip, src->dest_ip, sizeof(dst->dest_ip));
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Public API
|
|
******************************************************************************/
|
|
|
|
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";
|
|
}
|
|
}
|
|
|
|
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";
|
|
}
|
|
}
|
|
|
|
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";
|
|
}
|
|
}
|
|
|
|
const char *action_reason_to_string(enum action_reason action_reason)
|
|
{
|
|
switch (action_reason)
|
|
{
|
|
case ACTION_BYPASS_DUE_DEFAULT:
|
|
return "bypass_due_default";
|
|
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_SF:
|
|
return "forward_due_selected_sf";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
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";
|
|
}
|
|
}
|
|
|
|
// return NULL : error
|
|
// return !NULL : success
|
|
struct selected_chaining *selected_chaining_create(int chaining_size, uint64_t session_id, char *session_addr)
|
|
{
|
|
struct selected_chaining *chaining = (struct selected_chaining *)calloc(1, sizeof(struct selected_chaining));
|
|
assert(chaining);
|
|
chaining->chaining_used = 0;
|
|
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++)
|
|
{
|
|
struct selected_sf *item = &(chaining->chaining[i]);
|
|
selected_sf_init(item);
|
|
}
|
|
chaining->session_id = session_id;
|
|
chaining->session_addr = session_addr;
|
|
|
|
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: session %lu %s selected_chaining->chaining_size : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, chaining->chaining_size);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->chaining_used : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, chaining->chaining_used);
|
|
|
|
for (int i = 0; i < chaining->chaining_used; i++)
|
|
{
|
|
struct selected_sf *node = &(chaining->chaining[i]);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->rule_id : %lu", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->rule_id);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->traffic_type : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, traffic_type_to_string(node->traffic_type));
|
|
// sff
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sff_profile_id : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->sff_profile_id);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sff_forward_type : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, forward_type_to_string(node->sff_forward_type));
|
|
// sf
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_profile_id : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->sf_profile_id);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_need_skip : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->sf_need_skip);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_action : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, session_action_to_string(node->sf_action));
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_action_reason : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, action_reason_to_string(node->sf_action_reason));
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_connectivity->package_method : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, package_method_to_string(node->sf_connectivity.method));
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_connectivity->int_vlan_tag : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->sf_connectivity.int_vlan_tag);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_connectivity->ext_vlan_tag : %d", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, i, node->sf_connectivity.ext_vlan_tag);
|
|
LOG_DEBUG("%s: session %lu %s selected_chaining->node[%d]->sf_connectivity->dest_ip : %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, 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);
|
|
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++)
|
|
{
|
|
struct selected_sf *node = &(chaining->chaining[i]);
|
|
if (buff_size - buff_used > 0)
|
|
{
|
|
if (i != 0)
|
|
{
|
|
buff_used += snprintf(buff + buff_used, buff_size - buff_used, ",");
|
|
}
|
|
buff_used += snprintf(buff + buff_used, buff_size - buff_used,
|
|
"\"node[%d]\":{\"skip\":%d,\"rule_id\":%lu,\"sff_profile_id\":%d,\"sf_profile_id\":%d,\"traffic_type\":\"%s\",\"sff_forward_type\":\"%s\",\"sf_action\":\"%s\",\"reason\":\"%s\"}",
|
|
i, node->sf_need_skip, node->rule_id, node->sff_profile_id, node->sf_profile_id,
|
|
traffic_type_to_string(node->traffic_type), forward_type_to_string(node->sff_forward_type), session_action_to_string(node->sf_action), action_reason_to_string(node->sf_action_reason));
|
|
}
|
|
}
|
|
LOG_INFO("%s: session %lu %s selected_chaining_bref: %s}", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, buff);
|
|
}
|
|
|
|
void selected_chaining_uniq(struct selected_chaining *chaining)
|
|
{
|
|
if (chaining == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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));
|
|
|
|
struct maat_options *opts = maat_options_new();
|
|
if (opts == NULL)
|
|
{
|
|
LOG_ERROR("%s: unable create maat opts", LOG_TAG_POLICY);
|
|
goto error_out;
|
|
}
|
|
|
|
maat_options_set_logger(opts, "log/maat.log", (enum log_level)enforcer->config.log_level);
|
|
maat_options_set_instance_name(opts, instance);
|
|
maat_options_set_caller_thread_number(opts, thread_num);
|
|
maat_options_set_foreign_cont_dir(opts, enforcer->config.foreign_cont_dir);
|
|
maat_options_set_rule_effect_interval_ms(opts, enforcer->config.effect_interval_ms);
|
|
// TODO set enforcer->config.scan_detail
|
|
// Maat4 is not supported temporarily
|
|
|
|
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_options_set_json_file(opts, 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_options_set_redis(opts, enforcer->config.redis_server, redis_port_select, 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_options_set_iris(opts, enforcer->config.ful_cfg_dir, 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_options_set_stat_on(opts);
|
|
maat_options_set_stat_file(opts, enforcer->config.stat_file);
|
|
if (enforcer->config.perf_switch)
|
|
{
|
|
maat_options_set_perf_on(opts);
|
|
}
|
|
}
|
|
|
|
if (enforcer->config.deferred_load)
|
|
{
|
|
maat_options_set_deferred_load_on(opts);
|
|
}
|
|
|
|
if (strlen(enforcer->config.accept_tags))
|
|
{
|
|
maat_options_set_accept_tags(opts, enforcer->config.accept_tags);
|
|
}
|
|
|
|
enforcer->maat = maat_new(opts, enforcer->config.table_info);
|
|
if (enforcer->maat == NULL)
|
|
{
|
|
LOG_ERROR("%s: unable create maat", LOG_TAG_POLICY);
|
|
goto error_out;
|
|
}
|
|
|
|
maat_options_free(opts);
|
|
opts = NULL;
|
|
return enforcer;
|
|
|
|
error_out:
|
|
if (opts)
|
|
{
|
|
maat_options_free(opts);
|
|
opts = NULL;
|
|
}
|
|
policy_enforcer_destory(enforcer);
|
|
return NULL;
|
|
}
|
|
|
|
void policy_enforcer_destory(struct policy_enforcer *enforcer)
|
|
{
|
|
if (enforcer)
|
|
{
|
|
if (enforcer->maat)
|
|
{
|
|
maat_free(enforcer->maat);
|
|
enforcer->maat = NULL;
|
|
}
|
|
|
|
free(enforcer);
|
|
enforcer = NULL;
|
|
}
|
|
}
|
|
|
|
// return 0 : success
|
|
// return -1 : error
|
|
int policy_enforcer_register(struct policy_enforcer *enforcer)
|
|
{
|
|
LOG_INFO("%s: register policy callback ...", LOG_TAG_POLICY);
|
|
enforcer->compile_table_id = maat_get_table_id(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_get_table_id(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_get_table_id(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_table_ex_schema_register(enforcer->maat, "SERVICE_CHAINING_COMPILE",
|
|
chaining_param_new_cb,
|
|
chaining_param_free_cb,
|
|
chaining_param_dup_cb,
|
|
0, enforcer) != 0)
|
|
{
|
|
LOG_ERROR("%s: register SERVICE_CHAINING_COMPILE plugin extension callbacks failed", LOG_TAG_POLICY);
|
|
return -1;
|
|
}
|
|
|
|
if (maat_plugin_table_ex_schema_register(enforcer->maat, "SERVICE_FUNCTION_FORWARDER_PROFILE",
|
|
sff_param_new_cb,
|
|
sff_param_free_cb,
|
|
sff_param_dup_cb,
|
|
0, enforcer) != 0)
|
|
{
|
|
LOG_ERROR("%s: register SERVICE_FUNCTION_FORWARDER_PROFILE plugin extension callbacks failed", LOG_TAG_POLICY);
|
|
return -1;
|
|
}
|
|
|
|
if (maat_plugin_table_ex_schema_register(enforcer->maat, "SERVICE_FUNCTION_PROFILE",
|
|
sf_param_new_cb,
|
|
sf_param_free_cb,
|
|
sf_param_dup_cb,
|
|
0, enforcer) != 0)
|
|
{
|
|
LOG_ERROR("%s: register SERVICE_FUNCTION_PROFILE plugin extension callbacks failed", LOG_TAG_POLICY);
|
|
return -1;
|
|
}
|
|
LOG_INFO("%s: register policy callback success", LOG_TAG_POLICY);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int policy_enforce_chaining_size(struct policy_enforcer *enforcer)
|
|
{
|
|
return enforcer->config.max_chaining_size;
|
|
}
|
|
|
|
void policy_enforce_select_chainings(struct policy_enforcer *enforcer, struct selected_chainings *chainings, struct session_ctx *s_ctx, struct raw_pkt_parser *parser, uint64_t rule_id, int dir_is_i2e)
|
|
{
|
|
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;
|
|
struct selected_chaining *chaining = NULL;
|
|
|
|
snprintf(buffer, sizeof(buffer), "%lu", rule_id);
|
|
chaining_param = (struct chaining_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->compile_table_id, buffer, strlen(buffer));
|
|
if (chaining_param == NULL)
|
|
{
|
|
LOG_ERROR("%s: session %lu %s failed to get chaining parameter of policy %lu", LOG_TAG_POLICY, s_ctx->session_id, s_ctx->session_addr, rule_id);
|
|
return;
|
|
}
|
|
|
|
if (chaining_param->traffic_type == TRAFFIC_TYPE_RAW)
|
|
{
|
|
chaining = chainings->chaining_raw;
|
|
}
|
|
else
|
|
{
|
|
chaining = chainings->chaining_decrypted;
|
|
}
|
|
LOG_INFO("%s: session %lu %s enforce %s chaining rule %lu", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, traffic_type_to_string(chaining_param->traffic_type), rule_id);
|
|
|
|
for (int i = 0; i < chaining_param->sff_profile_ids_num && chaining->chaining_used < chaining->chaining_size; i++)
|
|
{
|
|
struct selected_sf *item = &(chaining->chaining[chaining->chaining_used]);
|
|
selected_sf_init(item);
|
|
|
|
item->rule_id = rule_id;
|
|
item->rule_vsys_id = chaining_param->vsys_id;
|
|
item->traffic_type = chaining_param->traffic_type;
|
|
item->sff_profile_id = chaining_param->sff_profile_ids[i];
|
|
item->sf_index = chaining->chaining_used;
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
snprintf(buffer, sizeof(buffer), "%u", item->sff_profile_id);
|
|
sff_param = (struct sff_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->sff_table_id, buffer, strlen(buffer));
|
|
if (sff_param == NULL)
|
|
{
|
|
LOG_ERROR("%s: session %lu %s failed to get sff parameter of profile %d, bypass current sff !!!", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, item->sff_profile_id);
|
|
item->sf_action = SESSION_ACTION_BYPASS;
|
|
item->sf_action_reason = ACTION_BYPASS_DUE_INVALID_POLICY;
|
|
chaining->chaining_used++;
|
|
continue;
|
|
}
|
|
item->sff_forward_type = sff_param->sff_forward_type;
|
|
|
|
memset(&array, 0, sizeof(array));
|
|
fixed_num_array_init(&array);
|
|
select_sf_by_nearby_and_adminstatus(enforcer, sff_param, &array);
|
|
LOG_DEBUG("%s: session %lu %s select sf from chaining rule %lu sff_profile %d, sf_profile_num (before filter: %d -> filter nearby/admin_status: %d)", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, rule_id, item->sff_profile_id, sff_param->sf_profile_ids_num, fixed_num_array_count_elem(&array));
|
|
if (fixed_num_array_count_elem(&array) == 0)
|
|
{
|
|
switch (sff_param->sff_exception.fail_action)
|
|
{
|
|
case FAILURE_ACTION_BYPASS:
|
|
item->sf_action = SESSION_ACTION_BYPASS;
|
|
item->sf_action_reason = ACTION_BYPASS_DUE_FAILURE_ACTION;
|
|
break;
|
|
case FAILURE_ACTION_BLOCK:
|
|
item->sf_action = SESSION_ACTION_BLOCK;
|
|
item->sf_action_reason = ACTION_BLOCK_DUE_FAILURE_ACTION;
|
|
break;
|
|
case FAILURE_ACTION_RE_DISPATCH:
|
|
if (sff_param->sff_exception.unavail_action == UNAVAILABLE_ACTION_BYPASSS)
|
|
{
|
|
item->sf_action = SESSION_ACTION_BYPASS;
|
|
item->sf_action_reason = ACTION_BYPASS_DUE_UNAVAILABLE_ACTION;
|
|
}
|
|
else // UNAVAILABLE_ACTION_BLOCK
|
|
{
|
|
item->sf_action = SESSION_ACTION_BLOCK;
|
|
item->sf_action_reason = ACTION_BLOCK_DUE_UNAVAILABLE_ACTION;
|
|
}
|
|
break;
|
|
}
|
|
LOG_DEBUG("%s: session %lu %s rule_id %lu sff_profile_id %d, no sf available after filtering by 'nearby & admin_status', %s", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, rule_id, item->sff_profile_id, action_reason_to_string(item->sf_action_reason));
|
|
chaining->chaining_used++;
|
|
sff_param_free(sff_param);
|
|
continue;
|
|
}
|
|
|
|
hash_value = raw_packet_parser_get_hash_value(parser, sff_param->sff_ldbc.method, dir_is_i2e);
|
|
item->sf_action = select_sf_by_ldbc(enforcer, s_ctx, sff_param, item, &array, hash_value);
|
|
if (item->sf_action != SESSION_ACTION_FORWARD)
|
|
{
|
|
chaining->chaining_used++;
|
|
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_table_get_ex_data(enforcer->maat, enforcer->sf_table_id, buffer, strlen(buffer));
|
|
if (sf_param == NULL)
|
|
{
|
|
LOG_ERROR("%s: session %lu %s failed to get sf parameter of profile %d, bypass current sff !!!", LOG_TAG_POLICY, chaining->session_id, chaining->session_addr, item->sf_profile_id);
|
|
item->sf_action = SESSION_ACTION_BYPASS;
|
|
item->sf_action_reason = ACTION_BYPASS_DUE_INVALID_POLICY;
|
|
chaining->chaining_used++;
|
|
sff_param_free(sff_param);
|
|
continue;
|
|
}
|
|
|
|
item->sf_vsys_id = sf_param->sf_vsys_id;
|
|
connectivity_copy(&item->sf_connectivity, &sf_param->sf_connectivity);
|
|
item->sf_dst_ip = inet_addr(sf_param->sf_connectivity.dest_ip);
|
|
chaining->chaining_used++;
|
|
|
|
sf_param_free(sf_param);
|
|
sff_param_free(sff_param);
|
|
}
|
|
|
|
selected_chaining_uniq(chaining);
|
|
chaining_param_free(chaining_param);
|
|
}
|