Merge pull request #5 from Telecominfraproject/plv_next_270224

Plv next 270224
This commit is contained in:
Olexandr, Mazur
2024-02-27 14:35:52 +02:00
committed by GitHub
6 changed files with 2268 additions and 121 deletions

View File

@@ -41,6 +41,7 @@ extern "C" {
*/
#define PID_TO_NAME(p, name) sprintf(name, "Ethernet%hu", p)
#define NAME_TO_PID(p, name) sscanf((name), "Ethernet%hu", (p))
#define VLAN_TO_NAME(v, name) sprintf((name), "Vlan%hu", (v))
struct plat_vlan_memberlist;
struct plat_port_vlan;
@@ -64,6 +65,18 @@ enum plat_ieee8021x_port_host_mode {
PLAT_802_1X_PORT_HOST_MODE_SINGLE_HOST,
};
enum plat_ieee8021x_das_auth_type {
PLAT_802_1X_DAS_AUTH_TYPE_ANY,
PLAT_802_1X_DAS_AUTH_TYPE_ALL,
PLAT_802_1X_DAS_AUTH_TYPE_SESSION_KEY,
};
enum plat_igmp_version {
PLAT_IGMP_VERSION_1,
PLAT_IGMP_VERSION_2,
PLAT_IGMP_VERSION_3
};
#define UCENTRAL_PORT_LLDP_PEER_INFO_MAX_MGMT_IPS (2)
/* Interface LLDP peer's data, as defined in interface.lldp.yml*/
struct plat_port_lldp_peer_info {
@@ -252,10 +265,27 @@ struct plat_port_l2 {
struct plat_ipv4 ipv4;
};
struct plat_igmp {
bool exist;
bool snooping_enabled;
bool querier_enabled;
bool fast_leave_enabled;
uint32_t query_interval;
uint32_t last_member_query_interval;
uint32_t max_response_time;
enum plat_igmp_version version;
size_t num_groups;
struct {
struct in_addr addr;
struct plat_ports_list *egress_ports_list;
} *groups;
};
struct plat_port_vlan {
struct plat_vlan_memberlist *members_list_head;
struct plat_ipv4 ipv4;
struct plat_dhcp dhcp;
struct plat_igmp igmp;
uint16_t id;
uint16_t mstp_instance;
};
@@ -282,6 +312,18 @@ struct plat_syslog_cfg {
char host[SYSLOG_CFG_FIELD_STR_MAX_LEN];
};
struct plat_enabled_service_cfg {
struct {
bool enabled;
} ssh;
struct telnet {
bool enabled;
} telnet;
struct {
bool enabled;
} http;
};
struct plat_rtty_cfg {
char id[RTTY_CFG_FIELD_STR_MAX_LEN];
char passwd[RTTY_CFG_FIELD_STR_MAX_LEN];
@@ -376,6 +418,31 @@ struct plat_radius_hosts_list {
struct plat_radius_host host;
};
struct plat_ieee8021x_dac_host {
char hostname[RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
char passkey[RADIUS_CFG_PASSKEY_STR_MAX_LEN];
};
struct plat_ieee8021x_dac_list {
struct plat_ieee8021x_dac_list *next;
struct plat_ieee8021x_dac_host host;
};
struct plat_port_isolation_session_ports {
struct plat_ports_list *ports_list;
};
struct plat_port_isolation_session {
uint64_t id;
struct plat_port_isolation_session_ports uplink;
struct plat_port_isolation_session_ports downlink;
};
struct plat_port_isolation_cfg {
struct plat_port_isolation_session *sessions;
size_t sessions_num;
};
struct plat_cfg {
struct plat_unit unit;
/* Alloc all ports, but access them only if bit is set. */
@@ -385,6 +452,7 @@ struct plat_cfg {
BITMAP_DECLARE(vlans_to_cfg, MAX_VLANS);
struct plat_metrics_cfg metrics;
struct plat_syslog_cfg *log_cfg;
struct plat_enabled_service_cfg enabled_services_cfg;
/* Port's interfaces (provide l2 iface w/o bridge caps) */
struct plat_port_l2 portsl2[MAX_NUM_OF_PORTS];
struct ucentral_router router;
@@ -393,7 +461,17 @@ struct plat_cfg {
/* Instance zero is for global instance (like common values in rstp) */
struct plat_stp_instance_cfg stp_instances[MAX_VLANS];
struct plat_radius_hosts_list *radius_hosts_list;
bool ieee8021x_is_auth_ctrl_enabled;
struct {
bool is_auth_ctrl_enabled;
bool bounce_port_ignore;
bool disable_port_ignore;
bool ignore_server_key;
bool ignore_session_key;
char server_key[RADIUS_CFG_PASSKEY_STR_MAX_LEN];
enum plat_ieee8021x_das_auth_type das_auth_type;
struct plat_ieee8021x_dac_list *das_dac_list;
} ieee8021x;
struct plat_port_isolation_cfg port_isolation_cfg;
};
struct plat_learned_mac_addr {
@@ -503,15 +581,57 @@ enum {
PLAT_REBOOT_CAUSE_UNAVAILABLE,
};
enum sfp_form_factor {
UCENTRAL_SFP_FORM_FACTOR_NA = 0,
UCENTRAL_SFP_FORM_FACTOR_SFP,
UCENTRAL_SFP_FORM_FACTOR_SFP_PLUS,
UCENTRAL_SFP_FORM_FACTOR_SFP_28,
UCENTRAL_SFP_FORM_FACTOR_SFP_DD,
UCENTRAL_SFP_FORM_FACTOR_QSFP,
UCENTRAL_SFP_FORM_FACTOR_QSFP_PLUS,
UCENTRAL_SFP_FORM_FACTOR_QSFP_28,
UCENTRAL_SFP_FORM_FACTOR_QSFP_DD
};
enum sfp_link_mode {
UCENTRAL_SFP_LINK_MODE_NA = 0,
UCENTRAL_SFP_LINK_MODE_1000_X,
UCENTRAL_SFP_LINK_MODE_2500_X,
UCENTRAL_SFP_LINK_MODE_4000_SR,
UCENTRAL_SFP_LINK_MODE_10G_SR,
UCENTRAL_SFP_LINK_MODE_25G_SR,
UCENTRAL_SFP_LINK_MODE_40G_SR,
UCENTRAL_SFP_LINK_MODE_50G_SR,
UCENTRAL_SFP_LINK_MODE_100G_SR,
};
struct plat_port_transceiver_info {
char vendor_name[64];
char part_number[64];
char serial_number[64];
char revision[64];
enum sfp_form_factor form_factor;
enum sfp_link_mode *supported_link_modes;
size_t num_supported_link_modes;
float temperature;
float tx_optical_power;
float rx_optical_power;
float max_module_power;
};
struct plat_port_info {
struct plat_port_counters stats;
struct plat_port_lldp_peer_info lldp_peer_info;
struct plat_ieee8021x_port_info ieee8021x_info;
struct plat_port_transceiver_info transceiver_info;
uint32_t uptime;
uint32_t speed;
uint8_t carrier_up;
uint8_t duplex;
uint8_t has_lldp_peer_info;
uint8_t has_transceiver_info;
char name[PORT_MAX_NAME_LEN];
};
@@ -525,6 +645,17 @@ struct plat_system_info {
double load_average[3]; /* 1, 5, 15 minutes load average */
};
struct plat_iee8021x_coa_counters {
uint64_t coa_req_received;
uint64_t coa_ack_sent;
uint64_t coa_nak_sent;
uint64_t coa_ignored;
uint64_t coa_wrong_attr;
uint64_t coa_wrong_attr_value;
uint64_t coa_wrong_session_context;
uint64_t coa_administratively_prohibited_req;
};
struct plat_state_info {
struct plat_poe_state poe_state;
struct plat_poe_port_state poe_ports_state[MAX_NUM_OF_PORTS];
@@ -532,10 +663,13 @@ struct plat_state_info {
struct plat_port_info *port_info;
int port_info_count;
struct plat_port_vlan *vlan_info;
size_t vlan_info_count;
struct plat_learned_mac_addr *learned_mac_list;
size_t learned_mac_list_size;
struct plat_system_info system_info;
struct plat_iee8021x_coa_counters ieee8021x_global_coa_counters;
};
struct plat_upgrade_info {

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,16 @@ struct gnma_radius_host_key {
char hostname[GNMA_RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
};
struct gnma_das_dac_host_key {
char hostname[GNMA_RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
};
typedef enum _gnma_das_auth_type_t {
GNMA_802_1X_DAS_AUTH_TYPE_ANY,
GNMA_802_1X_DAS_AUTH_TYPE_ALL,
GNMA_802_1X_DAS_AUTH_TYPE_SESSION_KEY,
} gnma_das_auth_type_t;
struct gnma_metadata {
char platform[GNMA_METADATA_STR_MAX_LEN];
char hwsku[GNMA_METADATA_STR_MAX_LEN];
@@ -59,6 +69,17 @@ typedef enum _gnma_port_stat_type_t {
} gnma_port_stat_type_t;
typedef enum _gnma_ieee8021x_das_dac_stat_type_t {
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_ACK_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_NAK_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_IGNORED_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_VALUE_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_SESSION_CONTEXT_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_ADMINISTRATIVELY_PROHIBITED_REQ_PKTS,
} gnma_ieee8021x_das_dac_stat_type_t;
struct gnma_alarm {
const char *id;
const char *resource;
@@ -269,6 +290,29 @@ struct gnma_fdb_entry {
char mac[18];
};
typedef enum _gnma_igmp_version_t {
GNMA_IGMP_VERSION_NA = 0,
GNMA_IGMP_VERSION_1 = 1,
GNMA_IGMP_VERSION_2 = 2,
GNMA_IGMP_VERSION_3 = 3
} gnma_igmp_version_t;
struct gnma_igmp_snoop_attr {
bool enabled;
bool querier_enabled;
bool fast_leave_enabled;
uint32_t query_interval;
uint32_t last_member_query_interval;
uint32_t max_response_time;
gnma_igmp_version_t version;
};
struct gnma_igmp_static_group_attr {
struct in_addr address;
size_t num_ports;
struct gnma_port_key *egress_ports;
};
int gnma_switch_create(/* TODO id */ /* TODO: attr (adr, login, psw) */);
int gnma_port_admin_state_set(struct gnma_port_key *port_key, bool up);
int gnma_port_speed_set(struct gnma_port_key *port_key, const char *speed);
@@ -403,14 +447,33 @@ int gnma_stp_ports_enable(uint32_t list_size, struct gnma_port_key *ports_list);
int gnma_stp_instance_set(uint16_t instance, uint16_t prio,
uint32_t list_size, uint16_t *vid_list);
int gnma_stp_vids_enable(uint32_t list_size, uint16_t *vid_list);
int gnma_stp_vids_enable_all(void);
int gnma_stp_vids_set(uint32_t list_size, uint16_t *vid_list, bool enable);
int gnma_stp_vids_set_all(bool enable);
int gnma_stp_vid_set(uint16_t vid, struct gnma_stp_attr *attr);
int gnma_stp_vid_bulk_get(struct gnma_stp_attr *list, ssize_t size);
int gnma_ieee8021x_system_auth_control_set(bool is_enabled);
int gnma_ieee8021x_system_auth_control_get(bool *is_enabled);
int gnma_ieee8021x_system_auth_clients_get(char *buf, size_t buf_size);
int gnma_ieee8021x_das_bounce_port_ignore_set(bool bounce_port_ignore);
int gnma_ieee8021x_das_bounce_port_ignore_get(bool *bounce_port_ignore);
int gnma_ieee8021x_das_disable_port_ignore_set(bool disable_port_ignore);
int gnma_ieee8021x_das_disable_port_ignore_get(bool *disable_port_ignore);
int gnma_ieee8021x_das_ignore_server_key_set(bool ignore_server_key);
int gnma_ieee8021x_das_ignore_server_key_get(bool *ignore_server_key);
int gnma_ieee8021x_das_ignore_session_key_set(bool ignore_session_key);
int gnma_ieee8021x_das_ignore_session_key_get(bool *ignore_session_key);
int gnma_ieee8021x_das_auth_type_key_set(gnma_das_auth_type_t auth_type);
int gnma_ieee8021x_das_auth_type_key_get(gnma_das_auth_type_t *auth_type);
int gnma_ieee8021x_das_dac_hosts_list_get(size_t *list_size,
struct gnma_das_dac_host_key *das_dac_keys_arr);
int gnma_ieee8021x_das_dac_host_add(struct gnma_das_dac_host_key *key,
const char *passkey);
int gnma_ieee8021x_das_dac_host_remove(struct gnma_das_dac_host_key *key);
int
gnma_iee8021x_das_dac_global_stats_get(uint32_t num_of_counters,
gnma_ieee8021x_das_dac_stat_type_t *counter_ids,
uint64_t *counters);
int gnma_radius_hosts_list_get(size_t *list_size,
struct gnma_radius_host_key *hosts_list);
@@ -419,6 +482,12 @@ int gnma_radius_host_add(struct gnma_radius_host_key *key, const char *passkey,
int gnma_radius_host_remove(struct gnma_radius_host_key *key);
int gnma_mac_address_list_get(size_t *list_size, struct gnma_fdb_entry *list);
int gnma_system_password_set(char *password);
int gnma_igmp_snooping_set(uint16_t vid, struct gnma_igmp_snoop_attr *attr);
int gnma_igmp_static_groups_set(uint16_t vid, size_t num_groups,
struct gnma_igmp_static_group_attr *groups);
int gnma_igmp_iface_groups_get(struct gnma_port_key *iface,
char *buf, size_t *buf_size);
struct gnma_change *gnma_change_create(void);
void gnma_change_destory(struct gnma_change *);

View File

@@ -44,6 +44,16 @@
#define RTTY_SESS_MAX (10)
#define ARR_FIND_VALUE_IDX(A, len, value) \
({ \
size_t it = 0; \
for ((it) = 0; (it) < (len); (++it)) { \
if ((A)[it] == (value)) \
break; \
} \
(it); \
})
static int plat_state_get(struct plat_state_info *state);
static void plat_state_deinit(struct plat_state_info *state);
static int plat_port_speed_get(uint16_t fp_p_id, uint32_t *speed);
@@ -137,6 +147,17 @@ plat_ieee8021x_system_auth_clients_get(uint16_t port_id,
} \
(res);})
#define PLAT_DAC_HOST_EXISTS_IN_CFG(_host, head) \
({bool res = false; \
struct plat_ieee8021x_dac_list *_pos; \
UCENTRAL_LIST_FOR_EACH_MEMBER((_pos), (head)) { \
if (strcmp((_host), ((_pos)->host.hostname)) == 0) { \
res = true; \
break; \
} \
} \
(res);})
/* For now, let's define abs max buf size as:
* 1024 (bytes) per client, 10 clients total at max for 100 ports;
* Bare minimum client info has ~600B size (raw json).
@@ -195,15 +216,6 @@ struct poe_port {
gnma_poe_port_priority_t priority;
};
/* Password is obfuscated and key changes all the time.
* So cache only actual hosts (ip / hostname), and do a single
* GNMI request to add host (with all parameters - passkey, port etc) upon
* every cfg reqest.
*/
struct radius_host {
struct gnma_radius_host_key key;
};
struct port {
struct gnma_port_key key;
struct {
@@ -244,6 +256,13 @@ struct plat_state {
} poe;
struct {
bool is_auth_control_enabled;
bool bounce_port_ignore;
bool disable_port_ignore;
bool ignore_server_key;
bool ignore_session_key;
gnma_das_auth_type_t das_auth_type;
struct gnma_das_dac_host_key *das_dac_keys_arr;
size_t das_dac_keys_arr_size;
} ieee8021x;
struct {
struct gnma_radius_host_key *hosts_keys_arr;
@@ -875,6 +894,98 @@ err:
return ret;
}
static int plat_state_ieee8021x_dac_list_init(void)
{
int ret;
free(plat_state.ieee8021x.das_dac_keys_arr);
plat_state.ieee8021x.das_dac_keys_arr = NULL;
plat_state.ieee8021x.das_dac_keys_arr_size = 0;
ret = gnma_ieee8021x_das_dac_hosts_list_get(&plat_state.ieee8021x.das_dac_keys_arr_size,
NULL);
if (ret && ret != GNMA_ERR_OVERFLOW) {
UC_LOG_CRIT("gnma_ieee8021x_das_dac_hosts_list_get failed");
plat_state.ieee8021x.das_dac_keys_arr_size = 0;
return ret;
}
/* No DAC hosts configured, no need to update cache. */
if (0 == plat_state.ieee8021x.das_dac_keys_arr_size)
return 0;
plat_state.ieee8021x.das_dac_keys_arr =
calloc(plat_state.ieee8021x.das_dac_keys_arr_size,
sizeof(*plat_state.ieee8021x.das_dac_keys_arr));
if (!plat_state.ieee8021x.das_dac_keys_arr) {
ret = -ENOMEM;
goto err;
}
ret = gnma_ieee8021x_das_dac_hosts_list_get(&plat_state.ieee8021x.das_dac_keys_arr_size,
plat_state.ieee8021x.das_dac_keys_arr);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_dac_hosts_list_get failed");
goto err;
}
return 0;
err:
free(plat_state.radius.hosts_keys_arr);
plat_state.radius.hosts_keys_arr = NULL;
plat_state.radius.hosts_keys_arr_size = 0;
return ret;
}
static int plat_state_ieee8021x_init(void)
{
int ret;
ret = gnma_ieee8021x_system_auth_control_get(&plat_state.ieee8021x.is_auth_control_enabled);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_system_auth_control_get failed");
return ret;
}
ret = gnma_ieee8021x_das_bounce_port_ignore_get(&plat_state.ieee8021x.bounce_port_ignore);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_bounce_port_ignore_get failed");
return ret;
}
ret = gnma_ieee8021x_das_disable_port_ignore_get(&plat_state.ieee8021x.disable_port_ignore);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_disable_port_ignore_get failed");
return ret;
}
ret = gnma_ieee8021x_das_ignore_server_key_get(&plat_state.ieee8021x.ignore_server_key);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_ignore_server_key_get failed");
return ret;
}
ret = gnma_ieee8021x_das_ignore_session_key_get(&plat_state.ieee8021x.ignore_session_key);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_ignore_session_key_get failed");
return ret;
}
ret = gnma_ieee8021x_das_auth_type_key_get(&plat_state.ieee8021x.das_auth_type);
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_das_auth_type_key_get failed");
return ret;
}
ret = plat_state_ieee8021x_dac_list_init();
if (ret) {
UC_LOG_CRIT("plat_state_ieee8021x_dac_list_init failed");
return ret;
}
return 0;
}
static int plat_state_init()
{
BITMAP_DECLARE(vlans, GNMA_MAX_VLANS);
@@ -892,9 +1003,15 @@ static int plat_state_init()
featsts[FEAT_CORE] = FEATSTS_FAIL;
ret = gnma_ieee8021x_system_auth_control_get(&plat_state.ieee8021x.is_auth_control_enabled);
ret = plat_state_ieee8021x_init();
if (ret) {
UC_LOG_CRIT("gnma_ieee8021x_system_auth_control_get failed");
UC_LOG_CRIT("plat_state_ieee8021x_init failed");
featsts[FEAT_AAA] = FEATSTS_FAIL;
}
ret = plat_state_radius_init();
if (ret) {
UC_LOG_CRIT("plat_state_radius_init failed");
featsts[FEAT_AAA] = FEATSTS_FAIL;
}
@@ -1012,12 +1129,6 @@ static int plat_state_init()
}
}
ret = plat_state_radius_init();
if (ret) {
UC_LOG_CRIT("plat_state_radius_init failed");
featsts[FEAT_AAA] = FEATSTS_FAIL;
}
if (featsts[FEAT_AAA] == FEATSTS_FAIL) {
UC_LOG_CRIT("AAA feature failed to initialize");
} else {
@@ -1458,16 +1569,6 @@ int plat_port_stats_get(uint16_t fp_p_id, struct plat_port_counters *stats)
uint64_t counters[ARRAY_LENGTH(stat_types)];
struct gnma_port_key gnma_port;
#define ARR_FIND_VALUE_IDX(A, len, value) \
({ \
size_t it = 0; \
for ((it) = 0; (it) < (len); (++it)) { \
if ((A)[it] == (value)) \
break; \
} \
(it); \
})
PID_TO_NAME(fp_p_id, gnma_port.name);
if (gnma_port_stats_get(&gnma_port, ARRAY_LENGTH(stat_types),
@@ -1522,7 +1623,6 @@ int plat_port_stats_get(uint16_t fp_p_id, struct plat_port_counters *stats)
stats->tx_packets +=
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_PORT_STAT_OUT_BCAST_PKTS)];
#undef ARR_FIND_VALUE_IDX
return 0;
}
@@ -1794,6 +1894,123 @@ err:
return ret;
}
int plat_port_transceiver_info_get(uint16_t port_id,
struct plat_port_transceiver_info *info)
{
/* TODO */
(void)((port_id));
(void)((info));
return -1;
}
static int plat_vlan_igmp_info_get(uint16_t vid, struct plat_igmp *info)
{
size_t list_size = 0, group_idx = 0;
struct plat_ports_list *port_node;
struct gnma_port_key iface = {0};
cJSON *groups = NULL, *group;
size_t buf_size = 0;
char *buf = NULL;
int ret = 0;
VLAN_TO_NAME(vid, iface.name);
ret = gnma_igmp_iface_groups_get(&iface, NULL, &buf_size);
if (ret == GNMA_OK && !buf_size)
return 0;
if (ret != GNMA_ERR_OVERFLOW)
return -1;
buf = calloc(buf_size, sizeof(*buf));
if (!buf)
return -1;
ret = gnma_igmp_iface_groups_get(&iface, buf, &buf_size);
if (ret != GNMA_OK) {
ret = -1;
goto err;
}
groups = cJSON_Parse(buf);
if (!groups) {
ret = -1;
goto err;
}
list_size = cJSON_GetArraySize(groups);
info->groups = calloc(list_size, sizeof(*info->groups));
if (!info->groups) {
ret = -1;
goto err;
}
info->num_groups = list_size;
cJSON_ArrayForEach(group, groups) {
cJSON *state, *gaddr, *e_ifaces, *e_iface;
state = cJSON_GetObjectItemCaseSensitive(group, "state");
if (!state || !cJSON_IsObject(state)) {
ret = -1;
goto err;
}
gaddr = cJSON_GetObjectItemCaseSensitive(state, "group");
if (!gaddr || !cJSON_GetStringValue(gaddr)) {
ret = -1;
goto err;
}
e_ifaces = cJSON_GetObjectItemCaseSensitive(state, "outgoing-interface");
if (!e_ifaces || !cJSON_IsArray(e_ifaces)) {
ret = -1;
goto err;
}
if (inet_pton(AF_INET, cJSON_GetStringValue(gaddr),
&info->groups[group_idx].addr) != 1) {
ret = -1;
goto err;
}
cJSON_ArrayForEach(e_iface, e_ifaces) {
if (!cJSON_GetStringValue(e_iface)) {
ret = -1;
goto err;
}
port_node = calloc(1, sizeof(*port_node));
if (!port_node) {
ret = -1;
goto err;
}
strncpy(port_node->name,
cJSON_GetStringValue(e_iface),
sizeof(port_node->name));
UCENTRAL_LIST_PUSH_MEMBER(
&info->groups[group_idx].egress_ports_list,
port_node);
}
group_idx++;
}
info->exist = true;
goto exit;
err:
if (info->groups) {
for (size_t i = 0; i < info->num_groups; ++i) {
UCENTRAL_LIST_DESTROY_SAFE(
&info->groups[i].egress_ports_list,
port_node);
}
}
free(info->groups);
exit:
cJSON_Delete(groups);
free(buf);
return ret;
}
static int
__poe_port_state_buf_parse(char *buf, size_t buf_size,
struct plat_poe_port_state *port_state)
@@ -1920,6 +2137,7 @@ __poe_state_buf_parse(char *buf, size_t buf_size,
{
cJSON *status;
cJSON *state;
cJSON *tmp;
state = cJSON_ParseWithLength(buf, buf_size);
if (!state)
@@ -1927,10 +2145,19 @@ __poe_state_buf_parse(char *buf, size_t buf_size,
poe_state->max_power_budget =
cJSON_GetNumberValue(cJSON_GetObjectItemCaseSensitive(state, "max-power-budget"));
/* For some reason, new BRCM images report this value as string, not value... */
tmp = cJSON_GetObjectItemCaseSensitive(state, "power-threshold");
if (!tmp || !cJSON_GetStringValue(tmp))
goto err;
poe_state->power_threshold =
cJSON_GetNumberValue(cJSON_GetObjectItemCaseSensitive(state, "power-threshold"));
(typeof(poe_state->power_threshold)) strtod(cJSON_GetStringValue(tmp), NULL);
tmp = cJSON_GetObjectItemCaseSensitive(state, "power-consumption");
if (!tmp || !cJSON_GetStringValue(tmp))
goto err;
poe_state->power_consumed =
cJSON_GetNumberValue(cJSON_GetObjectItemCaseSensitive(state, "power-consumption"));
(typeof(poe_state->power_consumed)) strtod(cJSON_GetStringValue(tmp), NULL);
status = cJSON_GetObjectItemCaseSensitive(state, "pse-oper-status");
if (!cJSON_GetStringValue(status))
@@ -2792,6 +3019,11 @@ err:
/* NOTE: In case of error this function left partial config */
int plat_vlan_rif_set(uint16_t vid, struct plat_ipv4 *ipv4)
{
struct gnma_igmp_snoop_attr igmp_snoop_attr = {
.enabled=false,
.querier_enabled=false,
.version=GNMA_IGMP_VERSION_NA
};
struct gnma_ip_prefix pref, pref_old;
uint16_t list_size;
int i;
@@ -2818,6 +3050,11 @@ int plat_vlan_rif_set(uint16_t vid, struct plat_ipv4 *ipv4)
return -1;
}
if (gnma_igmp_snooping_set(vid, &igmp_snoop_attr)) {
UC_LOG_DBG("Failed to set VLAN igmp.\n");
return -1;
}
if (list_size > 0 && !ipv4->exist) {
/* Force DHCP cache/state flush (delete), as at this point no
* dhcp cfg for this vlan exists, and it won't be 'restored'
@@ -2852,6 +3089,83 @@ int plat_vlan_rif_set(uint16_t vid, struct plat_ipv4 *ipv4)
return 0;
}
static int plat_vlan_igmp_set(uint16_t vid, struct plat_igmp *igmp)
{
struct gnma_igmp_static_group_attr *group_list;
struct plat_ports_list *e_port;
size_t group_idx, port_idx;
int ret;
struct gnma_igmp_snoop_attr attr = {
.last_member_query_interval = igmp->last_member_query_interval,
.fast_leave_enabled = igmp->fast_leave_enabled,
.max_response_time = igmp->max_response_time,
.querier_enabled = igmp->querier_enabled,
.query_interval = igmp->query_interval,
.enabled = igmp->snooping_enabled,
};
if (!igmp->exist)
attr.version = GNMA_IGMP_VERSION_NA;
else if (igmp->version == PLAT_IGMP_VERSION_1)
attr.version = GNMA_IGMP_VERSION_1;
else if (igmp->version == PLAT_IGMP_VERSION_2)
attr.version = GNMA_IGMP_VERSION_2;
else if (igmp->version == PLAT_IGMP_VERSION_3)
attr.version = GNMA_IGMP_VERSION_3;
else
return -1;
group_list = calloc(igmp->num_groups, sizeof(*group_list));
if (!group_list) {
UC_LOG_ERR("ENOMEM");
return -1;
}
for (group_idx = 0; group_idx < igmp->num_groups; group_idx++) {
group_list[group_idx].address = igmp->groups[group_idx].addr;
group_list[group_idx].num_ports = 0;
UCENTRAL_LIST_FOR_EACH_MEMBER(e_port, &igmp->groups[group_idx].egress_ports_list) {
group_list[group_idx].num_ports++;
}
group_list[group_idx].egress_ports = calloc(group_list[group_idx].num_ports,
sizeof(*group_list[group_idx].egress_ports));
if (!group_list[group_idx].egress_ports) {
UC_LOG_ERR("ENOMEM");
ret = -1;
goto err;
}
port_idx = 0;
UCENTRAL_LIST_FOR_EACH_MEMBER(e_port, &igmp->groups[group_idx].egress_ports_list) {
strncpy(group_list[group_idx].egress_ports[port_idx].name,
e_port->name,
sizeof(group_list[group_idx].egress_ports[port_idx].name));
port_idx++;
}
}
ret = gnma_igmp_snooping_set(vid, &attr);
if (ret) {
UC_LOG_ERR("gnma_igmp_snooping_set");
ret = -1;
goto err;
}
ret = gnma_igmp_static_groups_set(vid, igmp->num_groups, group_list);
if (ret) {
UC_LOG_ERR("gnma_igmp_static_groups_set");
ret = -1;
goto err;
}
err:
if (group_list)
for (group_idx = 0; group_idx < igmp->num_groups; group_idx++)
free(group_list[group_idx].egress_ports);
free(group_list);
return ret;
}
/* NOTE: In case of error this function left partial config */
int plat_portl2_rif_set(uint16_t fp_p_id, struct plat_ipv4 *ipv4)
{
@@ -2887,8 +3201,31 @@ int plat_portl2_rif_set(uint16_t fp_p_id, struct plat_ipv4 *ipv4)
static void plat_state_deinit(struct plat_state_info *state)
{
struct plat_ports_list *port_node;
for (int i = 0; i < state->port_info_count; i++) {
if (state->port_info[i].has_transceiver_info &&
state->port_info[i].transceiver_info.num_supported_link_modes) {
free(state->port_info[i].transceiver_info.supported_link_modes);
}
}
for (size_t i = 0; i < state->vlan_info_count; i++) {
struct plat_igmp *info = &state->vlan_info[i].igmp;
if (info->num_groups) {
for (size_t i = 0; i < info->num_groups; ++i) {
UCENTRAL_LIST_DESTROY_SAFE(
&info->groups[i].egress_ports_list,
port_node);
}
free(info->groups);
}
}
free(state->learned_mac_list);
free(state->port_info);
free(state->vlan_info);
*state = (struct plat_state_info){ 0 };
}
@@ -2954,6 +3291,11 @@ static int plat_port_info_get(struct plat_port_info **port_info, int *count)
pinfo[i].has_lldp_peer_info = 1;
}
if (!plat_port_transceiver_info_get(pid,
&pinfo[i].transceiver_info)) {
pinfo[i].has_transceiver_info = 1;
}
plat_ieee8021x_system_auth_clients_get(pid,
&ieee8021x_buf,
&ieee8021x_buf_size,
@@ -2973,6 +3315,54 @@ err:
return ret;
}
static int plat_vlan_info_get(struct plat_port_vlan **vlan_info, size_t *count)
{
BITMAP_DECLARE(vlans_bmp, GNMA_MAX_VLANS);
struct plat_port_vlan *vinfo = 0;
size_t num_vlans = 0;
size_t idx = 0;
size_t vid;
int ret;
BITMAP_CLEAR(vlans_bmp, GNMA_MAX_VLANS);
ret = gnma_vlan_list_get(vlans_bmp);
if (ret)
return -1;
BITMAP_FOR_EACH_BIT_SET(vid, vlans_bmp, GNMA_MAX_VLANS) {
num_vlans++;
}
if (!num_vlans) {
*count = 0;
return 0;
}
vinfo = calloc(num_vlans, sizeof(*vinfo));
if (!vinfo) {
UC_LOG_ERR("ENOMEM");
return -1;
}
memset(vinfo, 0, num_vlans * sizeof(*vinfo));
BITMAP_FOR_EACH_BIT_SET(vid, vlans_bmp, GNMA_MAX_VLANS) {
vinfo[idx].id = vid;
if (plat_vlan_igmp_info_get(vid, &vinfo[idx].igmp)) {
UC_LOG_DBG("plat_vlan_igmp_info_get failed");
return -1;
}
idx++;
if (idx >= num_vlans)
break;
}
*count = idx;
*vlan_info = vinfo;
return 0;
}
static int get_meminfo_cached_kib(uint64_t *cached)
{
size_t n;
@@ -3074,6 +3464,54 @@ err:
return ret;
}
static int
plat_state_ieee8021x_coa_global_counters_get(struct plat_iee8021x_coa_counters *stats)
{
gnma_ieee8021x_das_dac_stat_type_t stat_types[] = {
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_ACK_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_NAK_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_IGNORED_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_VALUE_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_SESSION_CONTEXT_PKTS,
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_ADMINISTRATIVELY_PROHIBITED_REQ_PKTS,
};
uint64_t counters[ARRAY_LENGTH(stat_types)];
if (gnma_iee8021x_das_dac_global_stats_get(ARRAY_LENGTH(stat_types),
&stat_types[0],
&counters[0]))
return -EINVAL;
stats->coa_req_received =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_PKTS)];
stats->coa_ack_sent =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_ACK_PKTS)];
stats->coa_nak_sent =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_NAK_PKTS)];
stats->coa_ignored =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_IGNORED_PKTS)];
stats->coa_wrong_attr =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_PKTS)];
stats->coa_wrong_attr_value =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_VALUE_PKTS)];
stats->coa_wrong_session_context =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_SESSION_CONTEXT_PKTS)];
stats->coa_administratively_prohibited_req =
counters[ARR_FIND_VALUE_IDX(stat_types, ARRAY_LENGTH(stat_types),
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_ADMINISTRATIVELY_PROHIBITED_REQ_PKTS)];
return 0;
}
static int plat_state_get(struct plat_state_info *state)
{
size_t i;
@@ -3092,10 +3530,16 @@ static int plat_state_get(struct plat_state_info *state)
if (plat_port_info_get(&state->port_info, &state->port_info_count))
return -1;
if (plat_vlan_info_get(&state->vlan_info, &state->vlan_info_count))
return -1;
if (plat_learned_mac_addrs_get(&state->learned_mac_list,
&state->learned_mac_list_size))
return -1;
if (plat_state_ieee8021x_coa_global_counters_get(&state->ieee8021x_global_coa_counters))
return -1;
return 0;
}
@@ -3111,6 +3555,12 @@ static int config_vlan_ipv4_apply(struct plat_cfg *cfg)
UC_LOG_DBG("Failed to set VLAN rif.\n");
return ret;
}
ret = plat_vlan_igmp_set(cfg->vlans[i].id, &cfg->vlans[i].igmp);
if (ret) {
UC_LOG_DBG("Failed to set VLAN igmp.\n");
return ret;
}
}
return 0;
@@ -3896,20 +4346,90 @@ static int plat_port_config_apply(struct plat_cfg *cfg)
return 0;
}
static int plat_dac_list_set(struct plat_ieee8021x_dac_list *hosts)
{
struct plat_ieee8021x_dac_list *iter;
bool cache_changed = false;
int ret = 0;
size_t i;
/*
* Check cache and remove any host that is not present in
* requested CFG (same as for VLAN: if not present in cfg = to
* be removed).
*/
for (i = 0; i < plat_state.ieee8021x.das_dac_keys_arr_size; ++i) {
if (!PLAT_DAC_HOST_EXISTS_IN_CFG(plat_state.ieee8021x.das_dac_keys_arr[i].hostname, &hosts)) {
UC_LOG_DBG("Removing DAC server <%s> (not in cfg, present on system)\n",
plat_state.ieee8021x.das_dac_keys_arr[i].hostname);
ret = gnma_ieee8021x_das_dac_host_remove(&plat_state.ieee8021x.das_dac_keys_arr[i]);
if (ret)
return ret;
cache_changed = true;
} else {
/* Special case, when host exists in cache and new CFG omitted password:
* - remove previous entry
* - recreate it without specifying password.
* Either way SONIC treats this host as if password is set
* explicitly, and might result in false-obfuscations of
* DaS / CoA exchange between DAC and switch.
*/
UCENTRAL_LIST_FOR_EACH_MEMBER(iter, &hosts) {
if (!strcmp(plat_state.ieee8021x.das_dac_keys_arr[i].hostname,
iter->host.hostname) &&
iter->host.passkey[0] == '\0') {
ret = gnma_ieee8021x_das_dac_host_remove(&plat_state.ieee8021x.das_dac_keys_arr[i]);
if (ret) {
UC_LOG_DBG("Failed to remove DAC host <%s> (new CFG pass is empty, tried to delete))\n",
plat_state.ieee8021x.das_dac_keys_arr[i].hostname);
return ret;
}
cache_changed = true;
break;
}
}
}
}
/* Add any new hosts that are present in requested CFG. */
UCENTRAL_LIST_FOR_EACH_MEMBER(iter, &hosts) {
struct gnma_das_dac_host_key key;
strcpy(key.hostname, iter->host.hostname);
ret = gnma_ieee8021x_das_dac_host_add(&key, iter->host.passkey);
if (ret)
return ret;
cache_changed = true;
}
/* Reinit DAC hosts cache. */
if (cache_changed)
plat_state_ieee8021x_dac_list_init();
return 0;
}
static int config_ieee8021x_apply(struct plat_cfg *cfg)
{
int ret;
if (cfg->ieee8021x_is_auth_ctrl_enabled != plat_state.ieee8021x.is_auth_control_enabled) {
if (cfg->ieee8021x.is_auth_ctrl_enabled != plat_state.ieee8021x.is_auth_control_enabled) {
UC_LOG_DBG("802.1x: changing global auth ctrl state from %d to %d",
plat_state.ieee8021x.is_auth_control_enabled,
cfg->ieee8021x_is_auth_ctrl_enabled);
ret = gnma_ieee8021x_system_auth_control_set(cfg->ieee8021x_is_auth_ctrl_enabled);
cfg->ieee8021x.is_auth_ctrl_enabled);
ret = gnma_ieee8021x_system_auth_control_set(cfg->ieee8021x.is_auth_ctrl_enabled);
if (ret) {
UC_LOG_DBG("802.1x: Failed to set global auth ctrl state.");
return ret;
}
plat_state.ieee8021x.is_auth_control_enabled = cfg->ieee8021x_is_auth_ctrl_enabled;
plat_state.ieee8021x.is_auth_control_enabled = cfg->ieee8021x.is_auth_ctrl_enabled;
}
ret = plat_dac_list_set(cfg->ieee8021x.das_dac_list);
if (ret) {
UC_LOG_DBG("802.1x: DAS: Failed to configure DAC hosts list.");
return ret;
}
ret = plat_radius_hosts_list_set(cfg->radius_hosts_list);
@@ -4003,6 +4523,7 @@ void plat_config_destroy(struct plat_cfg *cfg)
{
struct plat_vlan_memberlist *member_node = NULL;
struct plat_radius_hosts_list *hosts_node = NULL;
struct plat_ports_list *port_node;
size_t i;
if (!cfg)
@@ -4019,6 +4540,14 @@ void plat_config_destroy(struct plat_cfg *cfg)
cfg->vlans[i].members_list_head = NULL;
}
for (int i = 0; i < 0; ++i) {
UCENTRAL_LIST_DESTROY_SAFE(&cfg->port_isolation_cfg.sessions[i].uplink.ports_list,
port_node);
UCENTRAL_LIST_DESTROY_SAFE(&cfg->port_isolation_cfg.sessions[i].uplink.ports_list,
port_node);
}
free(cfg->port_isolation_cfg.sessions);
UCENTRAL_LIST_DESTROY_SAFE(&cfg->radius_hosts_list,
hosts_node);
}

View File

@@ -5,7 +5,7 @@
#define STR(x) #x
#define PLATFORM_REL_NUM 1.6
#define PLATFORM_BUILD_NUM 4
#define PLATFORM_BUILD_NUM 5
#ifndef PLATFORM_REVISION
#define PLATFORM_REVISION "Rel " XSTR(PLATFORM_REL_NUM) " build " XSTR(PLATFORM_BUILD_NUM)

View File

@@ -906,6 +906,171 @@ cfg_ethernet_ieee8021x_parse(cJSON *ieee8021x, struct plat_port *port)
return 0;
}
static int
cfg_ethernet_port_isolation_interface_parse(cJSON *iface,
struct plat_port_isolation_session_ports *ports) {
struct plat_ports_list *port_node = NULL;
cJSON *iface_list;
int i;
iface_list = cJSON_GetObjectItemCaseSensitive(iface, "interface-list");
if (!iface_list || !cJSON_IsArray(iface_list) ||
cJSON_GetArraySize(iface_list) == 0) {
UC_LOG_ERR("Ethernet obj 'port_isolation:interface-list' is invalid, parse failed\n");
return -1;
}
for (i = 0; i < cJSON_GetArraySize(iface_list); ++i) {
if (!cJSON_GetStringValue(cJSON_GetArrayItem(iface_list, i))) {
UC_LOG_ERR("Ethernet obj 'port_isolation:interface-list:%d' has invalid port name, parse failed\n",
i);
return -1;
}
port_node = calloc(1, sizeof(*port_node));
if (!port_node) {
UC_LOG_ERR("Failed alloc port list list\n");
return -1;
}
strcpy(port_node->name,
cJSON_GetStringValue(cJSON_GetArrayItem(iface_list, i)));
UCENTRAL_LIST_PUSH_MEMBER(&ports->ports_list, port_node);
}
return 0;
}
static int
cfg_ethernet_port_isolation_parse(cJSON *ethernet, struct plat_cfg *cfg) {
cJSON *eth = NULL, *port_isolation, *sessions, *session;
struct plat_port_isolation_session *session_arr;
struct plat_ports_list *port_node = NULL;
int i = 0, j = 0;
cJSON_ArrayForEach(eth, ethernet) {
port_isolation = cJSON_GetObjectItemCaseSensitive(eth, "port-isolation");
if (!port_isolation)
continue;
if (!cJSON_IsObject(port_isolation)) {
UC_LOG_ERR("Ethernet obj holds 'port_isolation' object of wrongful type, parse failed\n");
return -1;
}
sessions = cJSON_GetObjectItemCaseSensitive(port_isolation,
"sessions");
if (!sessions || !cJSON_IsArray(sessions)) {
UC_LOG_ERR("Ethernet obj holds 'port_isolation:sessions' array of wrongful type (or empty), parse failed\n");
return -1;
}
cJSON_ArrayForEach(session, sessions) {
cfg->port_isolation_cfg.sessions_num++;
}
}
if (cfg->port_isolation_cfg.sessions_num == 0) {
return 0;
}
session_arr = calloc(cfg->port_isolation_cfg.sessions_num,
sizeof(struct plat_port_isolation_session));
cfg->port_isolation_cfg.sessions = session_arr;
if (!session_arr) {
UC_LOG_ERR("Failed to alloc memory for port-isolation-cfg, parse failed\n");
return -1;
}
cJSON_ArrayForEach(eth, ethernet) {
port_isolation = cJSON_GetObjectItemCaseSensitive(eth, "port-isolation");
if (!port_isolation)
continue;
/*
* Highly unlikeable that the object is missing / invalid,
* as it was okay prior (parsing above).
* But this is still a sanity-check, in case if JSON
* got corrupted for some reason.
*/
if (!cJSON_IsObject(port_isolation)) {
UC_LOG_ERR("Ethernet obj holds 'port_isolation' object of wrongful type, parse failed\n");
return -1;
}
sessions = cJSON_GetObjectItemCaseSensitive(port_isolation,
"sessions");
if (!sessions || !cJSON_IsArray(sessions)) {
UC_LOG_ERR("Ethernet obj holds 'port_isolation:sessions' array of wrongful type (or empty), parse failed\n");
return -1;
}
cJSON_ArrayForEach(session, sessions) {
cJSON *id, *uplink, *downlink;
double session_arrid;
id = cJSON_GetObjectItemCaseSensitive(session, "id");
if (!id || !cJSON_IsNumber(id)) {
UC_LOG_ERR("Ethernet obj 'port_isolation:id' is invalid, parse failed\n");
goto err;
}
session_arrid = cJSON_GetNumberValue(id);
if (i > 0) {
for (int j = i - 1; j >= 0; --j) {
if ((double) session_arr[j].id == session_arrid) {
UC_LOG_ERR("Expected unique 'port_isolation:id', duplicate (%lu) detected, parse failed\n",
(uint64_t) session_arrid);
goto err;
}
}
}
session_arr[j].id = (uint64_t) session_arrid;
uplink = cJSON_GetObjectItemCaseSensitive(session,
"uplink");
if (!uplink || !cJSON_IsObject(uplink)) {
UC_LOG_ERR("Ethernet obj 'port_isolation:uplink' is invalid, parse failed\n");
goto err;
}
downlink = cJSON_GetObjectItemCaseSensitive(session,
"downlink");
if (!downlink || !cJSON_IsObject(downlink)) {
UC_LOG_ERR("Ethernet obj 'port_isolation:downlink' is invalid, parse failed\n");
goto err;
}
if (cfg_ethernet_port_isolation_interface_parse(uplink,
&session_arr[j].uplink)) {
UC_LOG_ERR("Ethernet obj 'port_isolation:uplink' parse failed\n");
goto err;
}
if (cfg_ethernet_port_isolation_interface_parse(downlink,
&session_arr[j].downlink)) {
UC_LOG_ERR("Ethernet obj 'port_isolation:downlink' parse failed\n");
goto err;
}
++i;
}
}
return 0;
err:
for (int j = i; j >= 0; --j) {
UCENTRAL_LIST_DESTROY_SAFE(&session_arr[j].uplink.ports_list,
port_node);
UCENTRAL_LIST_DESTROY_SAFE(&session_arr[j].downlink.ports_list,
port_node);
}
cfg->port_isolation_cfg.sessions = 0;
free(cfg->port_isolation_cfg.sessions);
return -1;
}
static int cfg_ethernet_parse(cJSON *ethernet, struct plat_cfg *cfg)
{
cJSON *eth = NULL;
@@ -986,6 +1151,11 @@ static int cfg_ethernet_parse(cJSON *ethernet, struct plat_cfg *cfg)
}
}
if (cfg_ethernet_port_isolation_parse(ethernet, cfg)) {
UC_LOG_ERR("port-isolation config parse faile\n");
return -1;
}
return 0;
}
@@ -1063,6 +1233,121 @@ static int cfg_port_interface_parse(cJSON *interface, struct plat_cfg *cfg)
return 0;
}
static int __cfg_vlan_interface_parse_multicast(cJSON *multicast,
struct plat_cfg *cfg,
uint16_t vid)
{
cJSON *igmp, *field, *group, *addr, *ports, *port;
struct plat_ports_list *e_port;
struct plat_igmp info = { /* default values */
.snooping_enabled = true,
.querier_enabled = false,
.fast_leave_enabled = false,
.query_interval = 60,
.last_member_query_interval = 60,
.max_response_time = 10,
.version = PLAT_IGMP_VERSION_3,
.num_groups = 0,
.groups = NULL
};
size_t group_idx;
if (!(igmp = cJSON_GetObjectItemCaseSensitive(multicast, "igmp")))
return 0;
/* handle igmp snooping parameters */
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "version")) && cJSON_IsNumber(field)) {
switch ((uint32_t)cJSON_GetNumberValue(field)) {
case 1:
info.version = PLAT_IGMP_VERSION_1;
break;
case 2:
info.version = PLAT_IGMP_VERSION_2;
break;
case 3:
info.version = PLAT_IGMP_VERSION_3;
break;
default:
UC_LOG_ERR("Invalid IGMP version %f", cJSON_GetNumberValue(field));
return -1;
}
}
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "snooping-enable")) && cJSON_IsBool(field))
info.snooping_enabled = cJSON_IsTrue(field);
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "querier-enable")) && cJSON_IsBool(field))
info.querier_enabled = cJSON_IsTrue(field);
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "fast-leave-enable")) && cJSON_IsBool(field))
info.fast_leave_enabled = cJSON_IsTrue(field);
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "query-interval")) && cJSON_IsNumber(field))
info.query_interval = cJSON_GetNumberValue(field);
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "last-member-query-interval")) && cJSON_IsNumber(field))
info.last_member_query_interval = cJSON_GetNumberValue(field);
if ((field = cJSON_GetObjectItemCaseSensitive(igmp, "max-response-time")) && cJSON_IsNumber(field))
info.max_response_time = cJSON_GetNumberValue(field);
field = cJSON_GetObjectItemCaseSensitive(igmp, "static-mcast-groups");
if (!field || !cJSON_IsArray(field))
goto skip_groups;
info.num_groups = cJSON_GetArraySize(field);
info.groups = calloc(info.num_groups, sizeof(*info.groups));
if (!info.groups)
goto err;
/* handle static groups */
group_idx = 0;
cJSON_ArrayForEach(group, field) {
addr = cJSON_GetObjectItemCaseSensitive(group, "address");
ports = cJSON_GetObjectItemCaseSensitive(group, "egress-ports");
if (!addr || !cJSON_IsString(addr) || !ports || !cJSON_IsArray(ports)) {
/* FIXME: workaround for parser issue */
addr = cJSON_GetObjectItemCaseSensitive(group, "static-mcast-groups[].address");
ports = cJSON_GetObjectItemCaseSensitive(group, "static-mcast-groups[].egress-ports");
if (!addr || !cJSON_IsString(addr) || !ports || !cJSON_IsArray(ports)) {
UC_LOG_ERR("Missing static group info\n");
goto err;
}
}
if (inet_pton(AF_INET, addr->valuestring, &info.groups[group_idx].addr.s_addr) != 1) {
UC_LOG_ERR("Failed to parse ip addr %s\n", addr->valuestring);
goto err;
}
/* handle egress ports */
cJSON_ArrayForEach(port, ports) {
e_port = calloc(1, sizeof(*e_port));
if (!e_port) {
UC_LOG_ERR("Can't alloc port node\n");
goto err;
}
if (!cJSON_IsString(port)){
UC_LOG_ERR("Invalid port name\n");
goto err;
}
strncpy(e_port->name, port->valuestring, sizeof(e_port->name));
UCENTRAL_LIST_PUSH_MEMBER(&info.groups[group_idx].egress_ports_list, e_port);
}
group_idx++;
}
skip_groups:
info.exist = info.snooping_enabled || info.querier_enabled;
cfg->vlans[vid].igmp = info;
return 0;
err:
if (info.groups) {
for (group_idx = 0; group_idx < info.num_groups; group_idx++) {
UCENTRAL_LIST_DESTROY_SAFE(
&info.groups[group_idx].egress_ports_list,
e_port);
}
}
free(info.groups);
return -1;
}
static int cfg_vlan_interface_parse(cJSON *interface, struct plat_cfg *cfg)
{
size_t i;
@@ -1076,6 +1361,7 @@ static int cfg_vlan_interface_parse(cJSON *interface, struct plat_cfg *cfg)
char *ipv4_subnet_str;
cJSON *select_ports;
cJSON *ipv4_subnet;
cJSON *multicast;
cJSON *vlan_tag;
cJSON *ethernet;
uint8_t tagged;
@@ -1141,6 +1427,7 @@ static int cfg_vlan_interface_parse(cJSON *interface, struct plat_cfg *cfg)
cfg->vlans[vid].dhcp.relay.enabled = false;
ipv4 = cJSON_GetObjectItemCaseSensitive(interface, "ipv4");
dhcp = cJSON_GetObjectItemCaseSensitive(ipv4, "dhcp");
multicast = cJSON_GetObjectItemCaseSensitive(ipv4, "multicast");
if (ipv4) {
/* TODO addressing */
ipv4_subnet_str = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(ipv4, "subnet"));
@@ -1181,6 +1468,13 @@ skip_subnet_old:
}
cfg->vlans[vid].ipv4.exist = true;
skip_subnet:
if (multicast) {
ret = __cfg_vlan_interface_parse_multicast(multicast, cfg, vid);
if (ret) {
UC_LOG_ERR("Failed parsing multicast config");
return ret;
}
}
if (!dhcp)
return 0;
@@ -1333,6 +1627,59 @@ static int cfg_services_parse(cJSON *services, struct plat_cfg *cfg)
}
}
/* Set default values in case if no cfg supplied */
cfg->enabled_services_cfg.ssh.enabled = false;
cfg->enabled_services_cfg.telnet.enabled = false;
cfg->enabled_services_cfg.http.enabled = false;
s = cJSON_GetObjectItemCaseSensitive(services, "ssh");
if (s) {
if (!cJSON_IsObject(s)) {
UC_LOG_ERR("Unexpected type of services:ssh: Object expected");
return -1;
}
cJSON *enable = cJSON_GetObjectItemCaseSensitive(s, "enable");
if (enable && !cJSON_IsBool(enable)) {
UC_LOG_ERR("Unexpected type of services:ssh:enable: Boolean expected");
return -1;
}
cfg->enabled_services_cfg.ssh.enabled = cJSON_IsTrue(enable);
}
s = cJSON_GetObjectItemCaseSensitive(services, "telnet");
if (s) {
if (!cJSON_IsObject(s)) {
UC_LOG_ERR("Unexpected type of services:telnet: Object expected");
return -1;
}
cJSON *enable = cJSON_GetObjectItemCaseSensitive(s, "enable");
if (enable && !cJSON_IsBool(enable)) {
UC_LOG_ERR("Unexpected type of services:telnet:enable: Boolean expected");
return -1;
}
cfg->enabled_services_cfg.telnet.enabled = cJSON_IsTrue(enable);
}
s = cJSON_GetObjectItemCaseSensitive(services, "http");
if (s) {
if (!cJSON_IsObject(s)) {
UC_LOG_ERR("Unexpected type of services:http: Object expected");
return -1;
}
cJSON *enable = cJSON_GetObjectItemCaseSensitive(s, "enable");
if (enable && !cJSON_IsBool(enable)) {
UC_LOG_ERR("Unexpected type of services:http:enable: Boolean expected");
return -1;
}
cfg->enabled_services_cfg.http.enabled = cJSON_IsTrue(enable);
}
return 0;
}
@@ -1353,7 +1700,7 @@ static int cfg_switch_ieee8021x_parse(cJSON *sw, struct plat_cfg *cfg)
/* It's safe to check against NULL cJSON obj.
* In case if option is missing - defaulting to 'false' is OK for us.
*/
cfg->ieee8021x_is_auth_ctrl_enabled = cJSON_IsTrue(auth_ctrl_enabled);
cfg->ieee8021x.is_auth_ctrl_enabled = cJSON_IsTrue(auth_ctrl_enabled);
radius = cJSON_GetObjectItemCaseSensitive(ieee8021x, "radius");
if (radius && !cJSON_IsArray(radius)) {
@@ -2511,6 +2858,10 @@ static void script_handle(cJSON **rpc)
UC_LOG_ERR("script message missing 'uri' parameter");
return;
}
script_reply(0, "pending", id);
UC_LOG_DBG("Script requested OK (pending. Waiting for plat to execute)\n");
memset(&file_path[0], 0, sizeof(file_path));
if (plat_diagnostic(&file_path[0])) {
UC_LOG_ERR("Script failed\n");
@@ -2518,9 +2869,6 @@ static void script_handle(cJSON **rpc)
return;
}
script_reply(0, "pending", id);
UC_LOG_DBG("Script requested OK\n");
/* Poll upgrade state - start periodical. */
while (access(file_path, F_OK))
sleep(1);
@@ -2766,14 +3114,135 @@ err:
return -1;
}
static int state_fill_transceiver_info(cJSON *root,
struct plat_port_transceiver_info *info)
{
char *form_factor[] = {
[UCENTRAL_SFP_FORM_FACTOR_NA] = "",
[UCENTRAL_SFP_FORM_FACTOR_SFP] = "SFP",
[UCENTRAL_SFP_FORM_FACTOR_SFP_PLUS] = "SFP+",
[UCENTRAL_SFP_FORM_FACTOR_SFP_28] = "SFP28",
[UCENTRAL_SFP_FORM_FACTOR_SFP_DD] = "SFP-DD",
[UCENTRAL_SFP_FORM_FACTOR_QSFP] = "QSFP",
[UCENTRAL_SFP_FORM_FACTOR_QSFP_PLUS] = "QSFP+",
[UCENTRAL_SFP_FORM_FACTOR_QSFP_28] = "QSFP28",
[UCENTRAL_SFP_FORM_FACTOR_QSFP_DD] = "QSFP-DD"
};
char *link_mode[] = {
[UCENTRAL_SFP_LINK_MODE_NA] = "",
[UCENTRAL_SFP_LINK_MODE_1000_X] = "1G",
[UCENTRAL_SFP_LINK_MODE_2500_X] = "2.5G",
[UCENTRAL_SFP_LINK_MODE_4000_SR] = "4G SR",
[UCENTRAL_SFP_LINK_MODE_10G_SR] = "10G SR",
[UCENTRAL_SFP_LINK_MODE_25G_SR] = "25G SR",
[UCENTRAL_SFP_LINK_MODE_40G_SR] = "40G SR",
[UCENTRAL_SFP_LINK_MODE_50G_SR] = "50G SR",
[UCENTRAL_SFP_LINK_MODE_100G_SR] = "100G SR"
};
cJSON *supp_modes, *mode;
size_t i;
if (!cJSON_AddStringToObject(root, "vendor-name",
info->vendor_name))
goto err;
if (!cJSON_AddStringToObject(root, "part-number",
info->part_number))
goto err;
if (!cJSON_AddStringToObject(root, "serial-number",
info->serial_number))
goto err;
if (!cJSON_AddStringToObject(root, "revision",
info->revision))
goto err;
if (!cJSON_AddNumberToObject(root, "temperature",
info->temperature))
goto err;
if (!cJSON_AddNumberToObject(root, "tx-optical-power",
info->tx_optical_power))
goto err;
if (!cJSON_AddNumberToObject(root, "rx-optical-power",
info->rx_optical_power))
goto err;
if (!cJSON_AddNumberToObject(root, "max-module-power",
info->max_module_power))
goto err;
if (!cJSON_AddStringToObject(root, "form-factor",
form_factor[info->form_factor]))
goto err;
if (!(supp_modes = cJSON_AddArrayToObject(root, "supported-link-modes")))
goto err;
for (i = 0; i < info->num_supported_link_modes; i++) {
if (!(mode = cJSON_CreateString(link_mode[info->supported_link_modes[i]])))
goto err;
if (!cJSON_AddItemToArray(supp_modes, mode)) {
cJSON_Delete(mode);
goto err;
}
}
return 0;
err:
return -1;
}
static int state_fill_interface_multicast(cJSON *root, struct plat_port_vlan *vlan)
{
cJSON *igmp, *enabled_groups, *group, *outgoing_ports;
struct plat_ports_list *port_node = NULL;
char ip_addr[] = {"255.255.255.255"};
int ret = -1;
size_t idx;
if (!vlan->igmp.exist)
return 0;
igmp = cJSON_AddObjectToObject(root, "igmp");
enabled_groups = cJSON_AddArrayToObject(igmp, "enabled-groups");
if (!igmp || !enabled_groups)
goto err;
for (idx = 0; idx < vlan->igmp.num_groups; idx++) {
if (!(group = cJSON_CreateObject()))
goto err;
if (!inet_ntop(AF_INET, &vlan->igmp.groups[idx].addr,
ip_addr, sizeof(ip_addr)))
goto err;
if (!(cJSON_AddStringToObject(group, "address", ip_addr)))
goto err;
if (!(outgoing_ports = cJSON_AddArrayToObject(group, "egress-ports")))
goto err;
UCENTRAL_LIST_FOR_EACH_MEMBER(
port_node,
&vlan->igmp.groups[idx].egress_ports_list) {
if (!cJSON_AddItemToArray(outgoing_ports, cJSON_CreateString(port_node->name)))
goto err;
}
if (!cJSON_AddItemToArray(enabled_groups, group))
goto err;
}
ret = 0;
err:
return ret;
}
static int state_fill_interfaces_data(cJSON *interfaces,
struct plat_state_info *state)
{
char location[] = { "/interfaces/XXXX" };
char vlan_name[] = { "VlanXXXX" };
cJSON *dns_servers;
cJSON *transceiver;
cJSON *interface;
cJSON *multicast;
cJSON *counters;
cJSON *clients;
cJSON *ipv4;
uint16_t id;
int ret;
int i;
@@ -2807,6 +3276,16 @@ static int state_fill_interfaces_data(cJSON *interfaces,
if (!ipv4)
goto err;
if (state->port_info[i].has_transceiver_info) {
transceiver = cJSON_AddObjectToObject(interface, "transceiver-info");
if (!transceiver)
goto err;
ret = state_fill_transceiver_info(transceiver,
&state->port_info[i].transceiver_info);
if (ret)
goto err;
}
ret = state_fill_interface_clients(clients,
&state->port_info[i]);
if (ret)
@@ -2832,23 +3311,46 @@ static int state_fill_interfaces_data(cJSON *interfaces,
}
/* TBD: find out (?) proper <location> */
{
char location[] = { "/interfaces/XXXX" };
uint16_t pid;
NAME_TO_PID(&id, state->port_info[i].name);
sprintf(location, "/interfaces/%hu", id);
NAME_TO_PID(&pid, state->port_info[i].name);
sprintf(location, "/interfaces/%hu", pid);
if (!cJSON_AddStringToObject(interface, "location",
location))
goto err;
}
if (!cJSON_AddStringToObject(interface, "location",
location))
goto err;
if (!jobj_u64_set(interface, "uptime",
state->system_info.uptime))
goto err;
}
for (i = 0; i < (int)state->vlan_info_count; i++) {
interface = cJSON_CreateObject();
if (!interface || !cJSON_AddItemToArray(interfaces, interface))
goto err;
clients = cJSON_AddArrayToObject(interface, "clients");
counters = cJSON_AddObjectToObject(interface, "counters");
dns_servers = cJSON_AddArrayToObject(interface, "dns_servers");
ipv4 = cJSON_AddObjectToObject(interface, "ipv4");
multicast = cJSON_AddObjectToObject(interface, "multicast");
if (!clients || !counters || !dns_servers || !ipv4 || !multicast)
goto err;
ret = state_fill_interface_multicast(multicast, &state->vlan_info[i]);
if (ret)
goto err;
sprintf(location, "/SVI/%u", state->vlan_info[i].id);
sprintf(vlan_name, "Vlan%u", state->vlan_info[i].id);
if (!cJSON_AddStringToObject(interface, "name", vlan_name))
goto err;
if (!cJSON_AddStringToObject(interface, "location", location))
goto err;
if (!jobj_u64_set(interface, "uptime", state->system_info.uptime))
goto err;
}
return 0;
err:
return -1;
@@ -3157,16 +3659,16 @@ static int
state_fill_unit_poe_data(cJSON *poe, struct plat_poe_state *poe_state_info)
{
if (!cJSON_AddNumberToObject(poe, "max-power-budget",
poe_state_info->max_power_budget))
if (!jobj_u64_set(poe, "max-power-budget",
poe_state_info->max_power_budget))
goto err;
if (!cJSON_AddNumberToObject(poe, "power-consumed",
poe_state_info->power_consumed))
if (!jobj_u64_set(poe, "power-consumed",
poe_state_info->power_consumed))
goto err;
if (!cJSON_AddNumberToObject(poe, "power-threshold",
poe_state_info->power_threshold))
if (!jobj_u64_set(poe, "power-threshold",
poe_state_info->power_threshold))
goto err;
if (!cJSON_AddStringToObject(poe, "power-status",
@@ -3178,8 +3680,51 @@ err:
return -1;
}
static int
state_fill_unit_ieee8021x_global_counters(cJSON *ieee8021x,
struct plat_iee8021x_coa_counters *c)
{
cJSON *das, *stats;
das = cJSON_AddObjectToObject(ieee8021x, "dynamic-authorization");
if (!das)
return -1;
stats = cJSON_AddObjectToObject(das, "stats");
if (!stats)
return -1;
if (!jobj_u64_set(stats, "coa_req_received",
c->coa_req_received))
return -1;
if (!jobj_u64_set(stats, "coa_ack_sent",
c->coa_ack_sent))
return -1;
if (!jobj_u64_set(stats, "coa_nak_sent",
c->coa_nak_sent))
return -1;
if (!jobj_u64_set(stats, "coa_ignored",
c->coa_ignored))
return -1;
if (!jobj_u64_set(stats, "coa_wrong_attr",
c->coa_wrong_attr))
return -1;
if (!jobj_u64_set(stats, "coa_wrong_attr_value",
c->coa_wrong_attr_value))
return -1;
if (!jobj_u64_set(stats, "coa_wrong_session_context",
c->coa_wrong_session_context))
return -1;
if (!jobj_u64_set(stats, "administratively_prohibited_req",
c->coa_administratively_prohibited_req))
return -1;
return 0;
}
static int state_fill_unit_data(cJSON *unit, struct plat_state_info *state)
{
cJSON *ieee8021x;
cJSON *loadArr;
cJSON *memory;
cJSON *poe;
@@ -3215,6 +3760,12 @@ static int state_fill_unit_data(cJSON *unit, struct plat_state_info *state)
if (!poe || state_fill_unit_poe_data(poe, &state->poe_state))
goto err;
ieee8021x = cJSON_AddObjectToObject(unit, "ieee8021x");
if (!ieee8021x ||
state_fill_unit_ieee8021x_global_counters(ieee8021x,
&state->ieee8021x_global_coa_counters))
goto err;
return 0;
err: