diff --git a/lib/inc/sai_redis.h b/lib/inc/sai_redis.h index 7473fb7a501d..8099c3ab3f5c 100644 --- a/lib/inc/sai_redis.h +++ b/lib/inc/sai_redis.h @@ -113,6 +113,7 @@ extern const sai_virtual_router_api_t redis_virtual_router_api; extern const sai_vlan_api_t redis_vlan_api; extern const sai_wred_api_t redis_wred_api; extern const sai_debug_counter_api_t redis_debug_counter_api; +extern const sai_nat_api_t redis_nat_api; #define UNREFERENCED_PARAMETER(X) @@ -194,6 +195,7 @@ REDIS_ENTRY_QUAD(l2mc_entry); REDIS_ENTRY_QUAD(mcast_fdb_entry); REDIS_ENTRY_QUAD(neighbor_entry); REDIS_ENTRY_QUAD(route_entry); +REDIS_ENTRY_QUAD(nat_entry); // BULK diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am index 264e26a70394..691290be0ec9 100644 --- a/lib/src/Makefile.am +++ b/lib/src/Makefile.am @@ -50,6 +50,7 @@ libsairedis_la_SOURCES = \ sai_redis_virtual_router.cpp \ sai_redis_vlan.cpp \ sai_redis_wred.cpp \ + sai_redis_nat.cpp \ sai_redis_generic_create.cpp \ sai_redis_generic_remove.cpp \ sai_redis_generic_set.cpp \ diff --git a/lib/src/sai_redis_generic_create.cpp b/lib/src/sai_redis_generic_create.cpp index ee3e4360ea58..66a5b52b4e3b 100644 --- a/lib/src/sai_redis_generic_create.cpp +++ b/lib/src/sai_redis_generic_create.cpp @@ -412,3 +412,4 @@ REDIS_ENTRY_CREATE(L2MC_ENTRY,l2mc_entry); REDIS_ENTRY_CREATE(MCAST_FDB_ENTRY,mcast_fdb_entry); REDIS_ENTRY_CREATE(NEIGHBOR_ENTRY,neighbor_entry); REDIS_ENTRY_CREATE(ROUTE_ENTRY,route_entry); +REDIS_ENTRY_CREATE(NAT_ENTRY,nat_entry); diff --git a/lib/src/sai_redis_generic_get.cpp b/lib/src/sai_redis_generic_get.cpp index 8eb35221927b..da28156de9e6 100644 --- a/lib/src/sai_redis_generic_get.cpp +++ b/lib/src/sai_redis_generic_get.cpp @@ -285,3 +285,4 @@ REDIS_ENTRY_GET(L2MC_ENTRY,l2mc_entry); REDIS_ENTRY_GET(MCAST_FDB_ENTRY,mcast_fdb_entry); REDIS_ENTRY_GET(NEIGHBOR_ENTRY,neighbor_entry); REDIS_ENTRY_GET(ROUTE_ENTRY,route_entry); +REDIS_ENTRY_GET(NAT_ENTRY,nat_entry); diff --git a/lib/src/sai_redis_generic_remove.cpp b/lib/src/sai_redis_generic_remove.cpp index 479810b651c5..db4befd75db2 100644 --- a/lib/src/sai_redis_generic_remove.cpp +++ b/lib/src/sai_redis_generic_remove.cpp @@ -156,3 +156,4 @@ REDIS_ENTRY_REMOVE(L2MC_ENTRY,l2mc_entry); REDIS_ENTRY_REMOVE(MCAST_FDB_ENTRY,mcast_fdb_entry); REDIS_ENTRY_REMOVE(NEIGHBOR_ENTRY,neighbor_entry); REDIS_ENTRY_REMOVE(ROUTE_ENTRY,route_entry); +REDIS_ENTRY_REMOVE(NAT_ENTRY,nat_entry); diff --git a/lib/src/sai_redis_generic_set.cpp b/lib/src/sai_redis_generic_set.cpp index adf5a993f4bb..4b7637a11a41 100644 --- a/lib/src/sai_redis_generic_set.cpp +++ b/lib/src/sai_redis_generic_set.cpp @@ -226,3 +226,4 @@ REDIS_ENTRY_SET(L2MC_ENTRY,l2mc_entry); REDIS_ENTRY_SET(MCAST_FDB_ENTRY,mcast_fdb_entry); REDIS_ENTRY_SET(NEIGHBOR_ENTRY,neighbor_entry); REDIS_ENTRY_SET(ROUTE_ENTRY,route_entry); +REDIS_ENTRY_SET(NAT_ENTRY,nat_entry); diff --git a/lib/src/sai_redis_interfacequery.cpp b/lib/src/sai_redis_interfacequery.cpp index 8a8e1c71a3d8..31f8a5d80720 100644 --- a/lib/src/sai_redis_interfacequery.cpp +++ b/lib/src/sai_redis_interfacequery.cpp @@ -255,6 +255,7 @@ sai_status_t sai_api_query( API_CASE(VLAN,vlan); API_CASE(WRED,wred); API_CASE(DEBUG_COUNTER,debug_counter); + API_CASE(NAT,nat); default: SWSS_LOG_ERROR("Invalid API type %d", sai_api_id); diff --git a/lib/src/sai_redis_nat.cpp b/lib/src/sai_redis_nat.cpp new file mode 100644 index 000000000000..29d8388d0023 --- /dev/null +++ b/lib/src/sai_redis_nat.cpp @@ -0,0 +1,72 @@ +#include "sai_redis.h" + +sai_status_t sai_bulk_create_nat_entry( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t sai_bulk_remove_nat_entry( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; + +} + +sai_status_t sai_bulk_set_nat_entry_attribute( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const sai_attribute_t *attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; + +} + +sai_status_t sai_bulk_get_nat_entry_attribute( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const uint32_t *attr_count, + _Inout_ sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; + +} + +REDIS_GENERIC_QUAD_ENTRY(NAT_ENTRY,nat_entry); +REDIS_GENERIC_QUAD(NAT_ZONE_COUNTER,nat_zone_counter); + +const sai_nat_api_t redis_nat_api = { + + REDIS_GENERIC_QUAD_API(nat_entry) + + sai_bulk_create_nat_entry, + sai_bulk_remove_nat_entry, + sai_bulk_set_nat_entry_attribute, + sai_bulk_get_nat_entry_attribute, + + REDIS_GENERIC_QUAD_API(nat_zone_counter) +}; diff --git a/meta/sai_meta.cpp b/meta/sai_meta.cpp index e9a074b88d13..0845f8d6703f 100644 --- a/meta/sai_meta.cpp +++ b/meta/sai_meta.cpp @@ -6757,3 +6757,283 @@ sai_status_t meta_sai_flush_fdb_entries( return flush_fdb_entries(switch_id, attr_count, attr_list); } + +// NAT + +sai_status_t meta_sai_validate_nat_entry( + _In_ const sai_nat_entry_t* nat_entry, + _In_ bool create) +{ + SWSS_LOG_ENTER(); + + if (nat_entry == NULL) + { + SWSS_LOG_ERROR("nat_entry pointer is NULL"); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_id_t vr = nat_entry->vr_id; + + if (vr == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("virtual router is set to null object id"); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t object_type = sai_object_type_query(vr); + + if (object_type == SAI_OBJECT_TYPE_NULL) + { + SWSS_LOG_ERROR("virtual router oid 0x%lx is not valid object type, " + "returned null object type", vr); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t expected = SAI_OBJECT_TYPE_VIRTUAL_ROUTER; + + if (object_type != expected) + { + SWSS_LOG_ERROR("virtual router oid 0x%lx type %d is wrong type, " + "expected object type %d", vr, object_type, expected); + + return SAI_STATUS_INVALID_PARAMETER; + } + + // check if virtual router exists + sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } }; + + std::string key_vr = sai_serialize_object_meta_key(meta_key_vr); + + if (!object_exists(key_vr)) + { + SWSS_LOG_ERROR("object key %s doesn't exist", key_vr.c_str()); + + return SAI_STATUS_INVALID_PARAMETER; + } + + // check if NAT entry exists + sai_object_meta_key_t meta_key_nat = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; + + std::string key_nat = sai_serialize_object_meta_key(meta_key_nat); + + if (create) + { + if (object_exists(key_nat)) + { + SWSS_LOG_ERROR("object key %s already exists", key_nat.c_str()); + + return SAI_STATUS_ITEM_ALREADY_EXISTS; + } + + return SAI_STATUS_SUCCESS; + } + + // set, get, remove + if (!object_exists(key_nat)) + { + SWSS_LOG_ERROR("object key %s doesn't exist", key_nat.c_str()); + + return SAI_STATUS_INVALID_PARAMETER; + } + + return SAI_STATUS_SUCCESS; +} + + +sai_status_t meta_sai_create_nat_entry( + _In_ const sai_nat_entry_t* nat_entry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list, + _In_ sai_create_nat_entry_fn create) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = meta_sai_validate_nat_entry(nat_entry, true); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + sai_object_meta_key_t meta_key = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; + + status = meta_generic_validation_create(meta_key, nat_entry->switch_id, attr_count, attr_list); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + if (create == NULL) + { + SWSS_LOG_ERROR("create function pointer is NULL"); + + return SAI_STATUS_FAILURE; + } + + status = create(nat_entry, attr_count, attr_list); + + META_LOG_STATUS(create, status); + + if (status == SAI_STATUS_SUCCESS) + { + SWSS_LOG_DEBUG("create status: %s", sai_serialize_status(status).c_str()); + } + else + { + SWSS_LOG_ERROR("create status: %s", sai_serialize_status(status).c_str()); + } + + if (status == SAI_STATUS_SUCCESS) + { + meta_generic_validation_post_create(meta_key, nat_entry->switch_id, attr_count, attr_list); + } + + return status; +} + +sai_status_t meta_sai_remove_nat_entry( + _In_ const sai_nat_entry_t* nat_entry, + _In_ sai_remove_nat_entry_fn remove) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = meta_sai_validate_nat_entry(nat_entry, false); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + sai_object_meta_key_t meta_key = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; + + status = meta_generic_validation_remove(meta_key); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + if (remove == NULL) + { + SWSS_LOG_ERROR("remove function pointer is NULL"); + + return SAI_STATUS_FAILURE; + } + + status = remove(nat_entry); + + META_LOG_STATUS(remove, status); + + if (status == SAI_STATUS_SUCCESS) + { + SWSS_LOG_DEBUG("remove status: %s", sai_serialize_status(status).c_str()); + } + else + { + SWSS_LOG_ERROR("remove status: %s", sai_serialize_status(status).c_str()); + } + + if (status == SAI_STATUS_SUCCESS) + { + meta_generic_validation_post_remove(meta_key); + } + + return status; +} + +sai_status_t meta_sai_set_nat_entry( + _In_ const sai_nat_entry_t* nat_entry, + _In_ const sai_attribute_t *attr, + _In_ sai_set_nat_entry_attribute_fn set) +{ + SWSS_LOG_ENTER(); + sai_status_t status = meta_sai_validate_nat_entry(nat_entry, false); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + sai_object_meta_key_t meta_key = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; + + status = meta_generic_validation_set(meta_key, attr); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + if (set == NULL) + { + SWSS_LOG_ERROR("set function pointer is NULL"); + + return SAI_STATUS_FAILURE; + } + + status = set(nat_entry, attr); + + META_LOG_STATUS(set, status); + + if (status == SAI_STATUS_SUCCESS) + { + SWSS_LOG_DEBUG("set status: %s", sai_serialize_status(status).c_str()); + } + else + { + SWSS_LOG_ERROR("set status: %s", sai_serialize_status(status).c_str()); + } + + if (status == SAI_STATUS_SUCCESS) + { + meta_generic_validation_post_set(meta_key, attr); + } + + return status; +} + +sai_status_t meta_sai_get_nat_entry( + _In_ const sai_nat_entry_t* nat_entry, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list, + _In_ sai_get_nat_entry_attribute_fn get) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = meta_sai_validate_nat_entry(nat_entry, false); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + sai_object_meta_key_t meta_key = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; + + status = meta_generic_validation_get(meta_key, attr_count, attr_list); + + if (status != SAI_STATUS_SUCCESS) + { + return status; + } + + if (get == NULL) + { + SWSS_LOG_ERROR("get function pointer is NULL"); + + return SAI_STATUS_FAILURE; + } + + status = get(nat_entry, attr_count, attr_list); + + META_LOG_STATUS(get, status); + + if (status == SAI_STATUS_SUCCESS) + { + meta_generic_validation_post_get(meta_key, nat_entry->switch_id, attr_count, attr_list); + } + + return status; +} diff --git a/meta/sai_meta.h b/meta/sai_meta.h index b68e81cffcc6..152e21b21c0b 100644 --- a/meta/sai_meta.h +++ b/meta/sai_meta.h @@ -107,6 +107,7 @@ META_QUAD_ENTRY(l2mc_entry); META_QUAD_ENTRY(mcast_fdb_entry); META_QUAD_ENTRY(neighbor_entry); META_QUAD_ENTRY(route_entry); +META_QUAD_ENTRY(nat_entry); // STATS diff --git a/meta/sai_serialize.h b/meta/sai_serialize.h index c405127a94bf..a9a22ff874cc 100644 --- a/meta/sai_serialize.h +++ b/meta/sai_serialize.h @@ -43,6 +43,9 @@ std::string sai_serialize_neighbor_entry( std::string sai_serialize_route_entry( _In_ const sai_route_entry_t &route_entry); +std::string sai_serialize_nat_entry( + _In_ const sai_nat_entry_t &nat_entry); + std::string sai_serialize_inseg_entry( _In_ const sai_inseg_entry_t &inseg_entry); @@ -207,6 +210,10 @@ void sai_deserialize_route_entry( _In_ const std::string& s, _In_ sai_route_entry_t &route_entry); +void sai_deserialize_nat_entry( + _In_ const std::string& s, + _In_ sai_nat_entry_t &nat_entry); + void sai_deserialize_inseg_entry( _In_ const std::string& s, _In_ sai_inseg_entry_t &inseg_entry); diff --git a/meta/saiserialize.cpp b/meta/saiserialize.cpp index 6ee1489cea32..6c99ff08955c 100644 --- a/meta/saiserialize.cpp +++ b/meta/saiserialize.cpp @@ -734,7 +734,7 @@ std::string sai_serialize_ipmc_entry( j["vr_id"] = sai_serialize_object_id(ipmc_entry.vr_id); j["type"] = sai_serialize_ipmc_entry_type(ipmc_entry.type); j["destination"] = sai_serialize_ip_address(ipmc_entry.destination); - j["sourte"] = sai_serialize_ip_address(ipmc_entry.source); + j["source"] = sai_serialize_ip_address(ipmc_entry.source); return j.dump(); } @@ -1646,6 +1646,65 @@ std::string sai_serialize_queue_deadlock_ntf( return j.dump(); } +json sai_serialize_nat_entry_key( + _In_ const sai_nat_entry_key_t& nat_entry_key) +{ + SWSS_LOG_ENTER(); + + json j; + + j["src_ip"] = sai_serialize_ipv4(nat_entry_key.src_ip); + j["dst_ip"] = sai_serialize_ipv4(nat_entry_key.dst_ip); + j["proto"] = sai_serialize_number(nat_entry_key.proto); + j["l4_src_port"] = sai_serialize_number(nat_entry_key.l4_src_port); + j["l4_dst_port"] = sai_serialize_number(nat_entry_key.l4_dst_port); + + return j; +} + +json sai_serialize_nat_entry_mask( + _In_ const sai_nat_entry_mask_t& nat_entry_mask) +{ + SWSS_LOG_ENTER(); + + json j; + + j["src_ip"] = sai_serialize_ipv4(nat_entry_mask.src_ip); + j["dst_ip"] = sai_serialize_ipv4(nat_entry_mask.dst_ip); + j["proto"] = sai_serialize_number(nat_entry_mask.proto); + j["l4_src_port"] = sai_serialize_number(nat_entry_mask.l4_src_port); + j["l4_dst_port"] = sai_serialize_number(nat_entry_mask.l4_dst_port); + + return j; +} + +json sai_serialize_nat_entry_data( + _In_ const sai_nat_entry_data_t& nat_entry_data) +{ + SWSS_LOG_ENTER(); + + json j; + + j["key"] = sai_serialize_nat_entry_key(nat_entry_data.key); + j["mask"] = sai_serialize_nat_entry_mask(nat_entry_data.mask); + + return j; +} + +std::string sai_serialize_nat_entry( + _In_ const sai_nat_entry_t& nat_entry) +{ + SWSS_LOG_ENTER(); + + json j; + + j["switch_id"] = sai_serialize_object_id(nat_entry.switch_id); + j["vr"] = sai_serialize_object_id(nat_entry.vr_id); + j["nat_data"] = sai_serialize_nat_entry_data(nat_entry.data); + + return j.dump(); +} + std::string sai_serialize_object_meta_key( _In_ const sai_object_meta_key_t& meta_key) { @@ -1674,6 +1733,10 @@ std::string sai_serialize_object_meta_key( key = sai_serialize_neighbor_entry(meta_key.objectkey.key.neighbor_entry); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + key = sai_serialize_nat_entry(meta_key.objectkey.key.nat_entry); + break; + default: if (meta->isnonobjectid) @@ -2657,6 +2720,55 @@ void sai_deserialize_route_entry( sai_deserialize_ip_prefix(j["dest"], route_entry.destination); } +void sai_deserialize_nat_entry_key( + _In_ const json& j, + _Out_ sai_nat_entry_key_t& nat_entry_key) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_ipv4(j["src_ip"], nat_entry_key.src_ip); + sai_deserialize_ipv4(j["dst_ip"], nat_entry_key.dst_ip); + sai_deserialize_number(j["proto"], nat_entry_key.proto); + sai_deserialize_number(j["l4_src_port"], nat_entry_key.l4_src_port); + sai_deserialize_number(j["l4_dst_port"], nat_entry_key.l4_dst_port); +} + +void sai_deserialize_nat_entry_mask( + _In_ const json& j, + _Out_ sai_nat_entry_mask_t& nat_entry_mask) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_ipv4(j["src_ip"], nat_entry_mask.src_ip); + sai_deserialize_ipv4(j["dst_ip"], nat_entry_mask.dst_ip); + sai_deserialize_number(j["proto"], nat_entry_mask.proto); + sai_deserialize_number(j["l4_src_port"], nat_entry_mask.l4_src_port); + sai_deserialize_number(j["l4_dst_port"], nat_entry_mask.l4_dst_port); +} + +void sai_deserialize_nat_entry_data( + _In_ const json& j, + _Out_ sai_nat_entry_data_t& nat_entry_data) +{ + SWSS_LOG_ENTER(); + + sai_deserialize_nat_entry_key(j["key"], nat_entry_data.key); + sai_deserialize_nat_entry_mask(j["mask"], nat_entry_data.mask); +} + +void sai_deserialize_nat_entry( + _In_ const std::string &s, + _Out_ sai_nat_entry_t& nat_entry) +{ + SWSS_LOG_ENTER(); + + json j = json::parse(s); + + sai_deserialize_object_id(j["switch_id"], nat_entry.switch_id); + sai_deserialize_object_id(j["vr"], nat_entry.vr_id); + sai_deserialize_nat_entry_data(j["nat_data"], nat_entry.data); +} + void sai_deserialize_attr_id( _In_ const std::string& s, _Out_ const sai_attr_metadata_t** meta) @@ -2725,6 +2837,10 @@ void sai_deserialize_object_meta_key( sai_deserialize_neighbor_entry(str_object_id, meta_key.objectkey.key.neighbor_entry); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + sai_deserialize_nat_entry(str_object_id, meta_key.objectkey.key.nat_entry); + break; + default: if (meta->isnonobjectid) diff --git a/syncd/syncd.cpp b/syncd/syncd.cpp index 7535c87d1605..9e221dae15ae 100644 --- a/syncd/syncd.cpp +++ b/syncd/syncd.cpp @@ -1803,6 +1803,18 @@ void InspectAsic() break; } + case SAI_OBJECT_TYPE_NAT_ENTRY: + { + sai_nat_entry_t nat_entry; + sai_deserialize_nat_entry(str_object_id, nat_entry); + + nat_entry.switch_id = translate_vid_to_rid(nat_entry.switch_id); + nat_entry.vr_id = translate_vid_to_rid(nat_entry.vr_id); + + status = sai_metadata_sai_nat_api->get_nat_entry_attribute(&nat_entry, attr_count, attr_list); + break; + } + default: { if (info->isnonobjectid) @@ -2624,6 +2636,7 @@ sai_object_id_t extractSwitchVid( sai_fdb_entry_t fdb_entry; sai_neighbor_entry_t neighbor_entry; sai_route_entry_t route_entry; + sai_nat_entry_t nat_entry; sai_object_id_t oid; switch (object_type) @@ -2640,6 +2653,10 @@ sai_object_id_t extractSwitchVid( sai_deserialize_route_entry(str_object_id, route_entry); return route_entry.switch_id; + case SAI_OBJECT_TYPE_NAT_ENTRY: + sai_deserialize_nat_entry(str_object_id, nat_entry); + return nat_entry.switch_id; + default: if (info->isnonobjectid) @@ -3181,6 +3198,10 @@ sai_status_t processEvent( sai_deserialize_route_entry(str_object_id, meta_key.objectkey.key.route_entry); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + sai_deserialize_nat_entry(str_object_id, meta_key.objectkey.key.nat_entry); + break; + default: SWSS_LOG_THROW("non object id %s is not supported yet, FIXME", info->objecttypename); diff --git a/syncd/syncd_applyview.cpp b/syncd/syncd_applyview.cpp index e4a68d53e2cd..798d656b28c3 100644 --- a/syncd/syncd_applyview.cpp +++ b/syncd/syncd_applyview.cpp @@ -574,6 +574,11 @@ class AsicView break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + sai_deserialize_nat_entry(o->str_object_id, o->meta_key.objectkey.key.nat_entry); + soNatEntries[o->str_object_id] = o; + break; + default: if (o->info->isnonobjectid) @@ -856,6 +861,7 @@ class AsicView StrObjectIdToSaiObjectHash soFdbs; StrObjectIdToSaiObjectHash soNeighbors; StrObjectIdToSaiObjectHash soRoutes; + StrObjectIdToSaiObjectHash soNatEntries; StrObjectIdToSaiObjectHash soOids; StrObjectIdToSaiObjectHash soAll; @@ -1183,6 +1189,10 @@ class AsicView soRoutes[currentObj->str_object_id] = currentObj; break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + soNatEntries[currentObj->str_object_id] = currentObj; + break; + default: SWSS_LOG_THROW("unsupported object type: %s", @@ -1309,6 +1319,10 @@ class AsicView soRoutes.erase(currentObj->str_object_id); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + soNatEntries[currentObj->str_object_id] = currentObj; + break; + default: SWSS_LOG_THROW("unsupported object type: %s", @@ -1684,6 +1698,27 @@ class AsicView break; } } + if (obj->getObjectType() == SAI_OBJECT_TYPE_NAT_ENTRY) + { + auto* meta = attr->getAttrMetadata(); + + switch (meta->attrid) + { + + case SAI_NAT_ENTRY_ATTR_HIT_BIT_COR: + case SAI_NAT_ENTRY_ATTR_HIT_BIT: + + // when reading asic view, ignore Nat entry hit-bit attribute + // this will result to not compare them during comparison logic + + SWSS_LOG_INFO("ignoring %s for %s", meta->attridname, obj->str_object_id.c_str()); + + continue; + + default: + break; + } + } obj->setAttr(attr); @@ -4810,6 +4845,78 @@ std::shared_ptr findCurrentBestMatchForSwitch( currentSwitchObj->getObjectStatus()); } +/** + * @brief Find current best match for NAT entry. + * + * + * @param currentView Current view. + * @param temporaryView Temporary view. + * @param temporaryObj Temporary object. + * + * @return Best match object if found or nullptr. + */ +std::shared_ptr findCurrentBestMatchForNatEntry( + _In_ const AsicView ¤tView, + _In_ const AsicView &temporaryView, + _In_ const std::shared_ptr &temporaryObj) +{ + SWSS_LOG_ENTER(); + + /* + * Make a copy here to not destroy object data, later + * on this data should be read only. + */ + + sai_object_meta_key_t mk = temporaryObj->meta_key; + + if (!exchangeTemporaryVidToCurrentVid(currentView, temporaryView, mk)) + { + /* + * Not all oids inside struct object were translated, so there is no + * matching object in current view, we need to return null. + */ + + return nullptr; + } + + std::string str_nat_entry = sai_serialize_nat_entry(mk.objectkey.key.nat_entry); + + /* + * Now when we have serialized NAT entry with temporary vr_id VID + * replaced to current vr_id VID we can do dictionary lookup for NAT entry. + */ + auto currentNatEntry = currentView.soNatEntries.find(str_nat_entry); + + if (currentNatEntry == currentView.soNatEntries.end()) + { + SWSS_LOG_DEBUG("unable to find NAT entry %s in current asic view", str_nat_entry.c_str()); + + return nullptr; + } + + /* + * We found the same NAT entry in current view! Just one extra check + * of object status if it's not processed yet. + */ + + auto currentNatObj = currentNatEntry->second; + + if (currentNatObj->getObjectStatus() == SAI_OBJECT_STATUS_NOT_PROCESSED) + { + return currentNatObj; + } + + + /* + * If we are here, that means this NAT entry was already processed, which + * can indicate a bug or somehow duplicated entries. + */ + + SWSS_LOG_THROW("found NAT entry %s in current view, but it status is %d, FATAL", + str_nat_entry.c_str(), + currentNatObj->getObjectStatus()); +} + std::shared_ptr findCurrentBestMatch( _In_ const AsicView ¤tView, _In_ const AsicView &temporaryView, @@ -4852,6 +4959,9 @@ std::shared_ptr findCurrentBestMatch( case SAI_OBJECT_TYPE_FDB_ENTRY: return findCurrentBestMatchForFdbEntry(currentView, temporaryView, temporaryObj); + case SAI_OBJECT_TYPE_NAT_ENTRY: + return findCurrentBestMatchForNatEntry(currentView, temporaryView, temporaryObj); + /* * We can have special case for switch since we know there should * be only one switch. @@ -5520,6 +5630,10 @@ void createNewObjectFromTemporaryObject( currentObj->str_object_id = sai_serialize_fdb_entry(currentObj->meta_key.objectkey.key.fdb_entry); break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + currentObj->str_object_id = sai_serialize_nat_entry(currentObj->meta_key.objectkey.key.nat_entry); + break; + default: SWSS_LOG_THROW("unexpected non object id type: %s", diff --git a/syncd/syncd_hard_reinit.cpp b/syncd/syncd_hard_reinit.cpp index 10d19a8a8e9d..22eab973f2cb 100644 --- a/syncd/syncd_hard_reinit.cpp +++ b/syncd/syncd_hard_reinit.cpp @@ -27,6 +27,7 @@ static StringHash g_switches; static StringHash g_fdbs; static StringHash g_routes; static StringHash g_neighbors; +static StringHash g_nat_entries; #define ENABLE_PERF @@ -1098,6 +1099,45 @@ void processRoutes(bool defaultOnly) } } +void processNatEntries() +{ + SWSS_LOG_ENTER(); + + for (auto &kv: g_nat_entries) + { + const std::string &strNatEntry = kv.first; + const std::string &asicKey = kv.second; + + sai_object_meta_key_t meta_key; + + meta_key.objecttype = SAI_OBJECT_TYPE_NAT_ENTRY; + + sai_deserialize_nat_entry(strNatEntry, meta_key.objectkey.key.nat_entry); + + processStructNonObjectIds(meta_key); + + std::shared_ptr list = g_attributesLists[asicKey]; + + sai_attribute_t *attrList = list->get_attr_list(); + + uint32_t attrCount = list->get_attr_count(); + + processAttributesForOids(SAI_OBJECT_TYPE_NAT_ENTRY, attrCount, attrList); + + sai_status_t status = sai_metadata_sai_nat_api-> + create_nat_entry(&meta_key.objectkey.key.nat_entry, attrCount, attrList); + + if (status != SAI_STATUS_SUCCESS) + { + listFailedAttributes(SAI_OBJECT_TYPE_NAT_ENTRY, attrCount, attrList); + + SWSS_LOG_THROW("failed to create_nat_entry %s: %s", + strNatEntry.c_str(), + sai_serialize_status(status).c_str()); + } + } +} + std::vector redisGetAsicStateKeys() { SWSS_LOG_ENTER(); @@ -1150,6 +1190,10 @@ void readAsicState() g_neighbors[strObjectId] = key; break; + case SAI_OBJECT_TYPE_NAT_ENTRY: + g_nat_entries[strObjectId] = key; + break; + case SAI_OBJECT_TYPE_SWITCH: g_switches[strObjectId] = key; g_oids[strObjectId] = key; @@ -1190,6 +1234,7 @@ void hardReinit() processOids(); processRoutes(true); processRoutes(false); + processNatEntries(); } #ifdef ENABLE_PERF diff --git a/vslib/inc/sai_vs.h b/vslib/inc/sai_vs.h index 6dfaed74d20a..aaa0225bc685 100644 --- a/vslib/inc/sai_vs.h +++ b/vslib/inc/sai_vs.h @@ -146,6 +146,7 @@ extern const sai_virtual_router_api_t vs_virtual_router_api; extern const sai_vlan_api_t vs_vlan_api; extern const sai_wred_api_t vs_wred_api; extern const sai_debug_counter_api_t vs_debug_counter_api; +extern const sai_nat_api_t vs_nat_api; // OID QUAD @@ -207,6 +208,7 @@ VS_ENTRY_QUAD(l2mc_entry); VS_ENTRY_QUAD(mcast_fdb_entry); VS_ENTRY_QUAD(neighbor_entry); VS_ENTRY_QUAD(route_entry); +VS_ENTRY_QUAD(nat_entry); // STATS diff --git a/vslib/src/Makefile.am b/vslib/src/Makefile.am index b3877b83254d..b803bd893468 100644 --- a/vslib/src/Makefile.am +++ b/vslib/src/Makefile.am @@ -50,6 +50,7 @@ libsaivs_la_SOURCES = \ sai_vs_virtual_router.cpp \ sai_vs_vlan.cpp \ sai_vs_wred.cpp \ + sai_vs_nat.cpp \ sai_vs_generic_create.cpp \ sai_vs_generic_get.cpp \ sai_vs_generic_remove.cpp \ diff --git a/vslib/src/sai_vs_generic_create.cpp b/vslib/src/sai_vs_generic_create.cpp index 49f4f448d767..14d8b8b36326 100644 --- a/vslib/src/sai_vs_generic_create.cpp +++ b/vslib/src/sai_vs_generic_create.cpp @@ -706,3 +706,4 @@ VS_ENTRY_CREATE(L2MC_ENTRY,l2mc_entry); VS_ENTRY_CREATE(MCAST_FDB_ENTRY,mcast_fdb_entry); VS_ENTRY_CREATE(NEIGHBOR_ENTRY,neighbor_entry); VS_ENTRY_CREATE(ROUTE_ENTRY,route_entry); +VS_ENTRY_CREATE(NAT_ENTRY, nat_entry); diff --git a/vslib/src/sai_vs_generic_get.cpp b/vslib/src/sai_vs_generic_get.cpp index ddfd52f50755..a5da66e24282 100644 --- a/vslib/src/sai_vs_generic_get.cpp +++ b/vslib/src/sai_vs_generic_get.cpp @@ -209,3 +209,4 @@ VS_ENTRY_GET(L2MC_ENTRY,l2mc_entry); VS_ENTRY_GET(MCAST_FDB_ENTRY,mcast_fdb_entry); VS_ENTRY_GET(NEIGHBOR_ENTRY,neighbor_entry); VS_ENTRY_GET(ROUTE_ENTRY,route_entry); +VS_ENTRY_GET(NAT_ENTRY, nat_entry); diff --git a/vslib/src/sai_vs_generic_remove.cpp b/vslib/src/sai_vs_generic_remove.cpp index 7c208954f954..6d39e3267ecc 100644 --- a/vslib/src/sai_vs_generic_remove.cpp +++ b/vslib/src/sai_vs_generic_remove.cpp @@ -201,3 +201,4 @@ VS_ENTRY_REMOVE(L2MC_ENTRY,l2mc_entry); VS_ENTRY_REMOVE(MCAST_FDB_ENTRY,mcast_fdb_entry); VS_ENTRY_REMOVE(NEIGHBOR_ENTRY,neighbor_entry); VS_ENTRY_REMOVE(ROUTE_ENTRY,route_entry); +VS_ENTRY_REMOVE(NAT_ENTRY, nat_entry); diff --git a/vslib/src/sai_vs_generic_set.cpp b/vslib/src/sai_vs_generic_set.cpp index 109b4c35b969..b0e30646eafb 100644 --- a/vslib/src/sai_vs_generic_set.cpp +++ b/vslib/src/sai_vs_generic_set.cpp @@ -71,3 +71,4 @@ VS_ENTRY_SET(L2MC_ENTRY,l2mc_entry); VS_ENTRY_SET(MCAST_FDB_ENTRY,mcast_fdb_entry); VS_ENTRY_SET(NEIGHBOR_ENTRY,neighbor_entry); VS_ENTRY_SET(ROUTE_ENTRY,route_entry); +VS_ENTRY_SET(NAT_ENTRY, nat_entry); diff --git a/vslib/src/sai_vs_interfacequery.cpp b/vslib/src/sai_vs_interfacequery.cpp index cea17dfca23f..c217e31bbfe0 100644 --- a/vslib/src/sai_vs_interfacequery.cpp +++ b/vslib/src/sai_vs_interfacequery.cpp @@ -916,6 +916,7 @@ sai_status_t sai_api_query( API_CASE(VLAN,vlan); API_CASE(WRED,wred); API_CASE(DEBUG_COUNTER,debug_counter); + API_CASE(NAT,nat); default: SWSS_LOG_ERROR("Invalid API type %d", sai_api_id); diff --git a/vslib/src/sai_vs_nat.cpp b/vslib/src/sai_vs_nat.cpp new file mode 100644 index 000000000000..40853b922e07 --- /dev/null +++ b/vslib/src/sai_vs_nat.cpp @@ -0,0 +1,70 @@ +#include "sai_vs.h" +#include "sai_vs_internal.h" + +sai_status_t vs_bulk_create_nat_entry( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const uint32_t *attr_count, + _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t vs_bulk_remove_nat_entry( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t vs_bulk_set_nat_entry_attribute( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const sai_attribute_t *attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t vs_bulk_get_nat_entry_attribute( + _In_ uint32_t object_count, + _In_ const sai_nat_entry_t *nat_entry, + _In_ const uint32_t *attr_count, + _Inout_ sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, + _Out_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +VS_GENERIC_QUAD_ENTRY(NAT_ENTRY,nat_entry); +VS_GENERIC_QUAD(NAT_ZONE_COUNTER,nat_zone_counter); + +const sai_nat_api_t vs_nat_api = { + + VS_GENERIC_QUAD_API(nat_entry) + + vs_bulk_create_nat_entry, + vs_bulk_remove_nat_entry, + vs_bulk_set_nat_entry_attribute, + vs_bulk_get_nat_entry_attribute, + + VS_GENERIC_QUAD_API(nat_zone_counter) +};