diff options
author | Amir Levy <alevy@codeaurora.org> | 2017-07-03 10:51:22 +0300 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-07-08 23:43:13 -0700 |
commit | dfda87d642c35b9185081a837182a9cc182dd0f7 (patch) | |
tree | f261e5b3440741b1538cb9266c519b5a1a9cef1a /ipanat | |
parent | 1d6dbdcef40b4f22303183cdc7c178594f8ecd0a (diff) | |
download | ipacfg-mgr-dfda87d642c35b9185081a837182a9cc182dd0f7.tar.gz |
ipanat: Add support for Multi PDN
IPAv4 HW presents new Multi PDN with NAT functionality.
This change adds SW support of this feature.
Change-Id: I25ff6a52261fad60ecea4be044b0e15ba55821f5
Diffstat (limited to 'ipanat')
-rw-r--r-- | ipanat/inc/ipa_nat_drv.h | 30 | ||||
-rw-r--r-- | ipanat/inc/ipa_nat_drvi.h | 38 | ||||
-rw-r--r-- | ipanat/src/Makefile.am | 19 | ||||
-rw-r--r-- | ipanat/src/ipa_nat_drv.c | 42 | ||||
-rw-r--r-- | ipanat/src/ipa_nat_drvi.c | 93 |
5 files changed, 207 insertions, 15 deletions
diff --git a/ipanat/inc/ipa_nat_drv.h b/ipanat/inc/ipa_nat_drv.h index 04e3af9..4ef8779 100644 --- a/ipanat/inc/ipa_nat_drv.h +++ b/ipanat/inc/ipa_nat_drv.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2013, The Linux Foundation. All rights reserved. +Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -38,6 +38,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @target_port: destination port * @private_port: private port * @protocol: protocol of rule (tcp/udp) + * @pdn_index: PDN index in the PDN config table */ typedef struct { uint32_t target_ip; @@ -46,9 +47,22 @@ typedef struct { uint16_t private_port; uint16_t public_port; uint8_t protocol; + uint8_t pdn_index; } ipa_nat_ipv4_rule; /** +* struct ipa_nat_pdn_entry - holds a PDN entry data +* @public_ip: PDN's public ip address +* @src_metadata: metadata to be used for source NAT metadata replacement +* @dst_metadata: metadata to be used for destination NAT metadata replacement +*/ +typedef struct { + uint32_t public_ip; + uint32_t src_metadata; + uint32_t dst_metadata; +} ipa_nat_pdn_entry; + +/** * ipa_nat_add_ipv4_tbl() - create ipv4 nat table * @public_ip_addr: [in] public ipv4 address * @number_of_entries: [in] number of nat entries @@ -114,3 +128,17 @@ int ipa_nat_query_timestamp(uint32_t table_handle, uint32_t rule_handle, uint32_t *time_stamp); + +/** +* ipa_nat_modify_pdn() - modify single PDN entry in the PDN config table +* @table_handle: [in] handle of ipv4 nat table +* @pdn_index : [in] the index of the entry to be modified +* @pdn_info : [in] values for the PDN entry to be changed +* +* Modify a PDN entry +* +* Returns: 0 On Success, negative on failure +*/ +int ipa_nat_modify_pdn(uint32_t tbl_hdl, + uint8_t pdn_index, + ipa_nat_pdn_entry *pdn_info); diff --git a/ipanat/inc/ipa_nat_drvi.h b/ipanat/inc/ipa_nat_drvi.h index 6f9b1bd..1896a3e 100644 --- a/ipanat/inc/ipa_nat_drvi.h +++ b/ipanat/inc/ipa_nat_drvi.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2013, The Linux Foundation. All rights reserved. +Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -215,8 +215,8 @@ typedef struct { | Proto | TimeStamp(3B) | Flags(2B) | IP check sum Diff(2B)| | (1B) | |EN|FIN|Resv | | | ----------------------------------------------------------------------------------- - | TCP/UDP checksum | Reserved(2B) | SW Specific Parameters(4B) | - | diff (2B) | | + | TCP/UDP checksum |PDN info| Reserved| SW Specific Parameters(4B) | + | diff (2B) | (1B) | (1B) | | ----------------------------------------------------------------------------------- Dont change below structure definition. @@ -240,11 +240,23 @@ struct ipa_nat_rule { ------------------------------------ | index table | prev index | | entry | | - ------------------------------------ + ------------------------------------ --------------------------------------------------*/ uint64_t sw_spec_params:32; - uint64_t rsvd2:16; + uint64_t rsvd2:8; + + /*----------------------------------------- + 8 bit PDN info is interpreted as following + ------------------------------------ + | 4 bits | 4 bits | + ------------------------------------ + | PDN index | reserved | + | | | + ------------------------------------ + -------------------------------------------*/ + uint64_t rsvd3:4; + uint64_t pdn_index:4; uint64_t tcp_udp_chksum:16; }; @@ -275,7 +287,18 @@ struct ipa_nat_sw_rule { --------------------------------------------------*/ uint64_t prev_index:16; uint64_t indx_tbl_entry:16; - uint64_t rsvd2:16; + uint64_t rsvd2 :8; + /*----------------------------------------- + 8 bit PDN info is interpreted as following + ------------------------------------ + | 4 bits | 4 bits | + ------------------------------------ + | PDN index | reserved | + | | | + ------------------------------------ + -------------------------------------------*/ + uint64_t rsvd3 :4; + uint64_t pdn_index :4; uint64_t tcp_udp_chksum:16; }; #define IPA_NAT_TABLE_ENTRY_SIZE 32 @@ -326,6 +349,7 @@ struct ipa_nat_cache { struct ipa_nat_ip4_table_cache ip4_tbl[IPA_NAT_MAX_IP4_TBLS]; int ipa_fd; uint8_t table_cnt; + enum ipa_hw_type ver; }; struct ipa_nat_indx_tbl_sw_rule { @@ -402,6 +426,8 @@ int ipa_nati_query_timestamp(uint32_t tbl_hdl, uint32_t rule_hdl, uint32_t *time_stamp); +int ipa_nati_modify_pdn(struct ipa_ioc_nat_pdn_entry *entry); + int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl, const ipa_nat_ipv4_rule *clnt_rule, uint32_t *rule_hdl); diff --git a/ipanat/src/Makefile.am b/ipanat/src/Makefile.am index 8bdb9b8..8e2d005 100644 --- a/ipanat/src/Makefile.am +++ b/ipanat/src/Makefile.am @@ -1,21 +1,38 @@ AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs +if KERNELMODULES +AM_CFLAGS += -I./../inc $(KERNEL_DIR)/include +else AM_CFLAGS += -I./../inc +endif #AM_CFLAGS += -DDEBUG -g common_CFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ +if !KERNELMODULES common_LDFLAGS = -lrt @GLIB_LIBS@ +endif + +if KERNELMODULES +library_includedir = ../inc $(KERNEL_DIR)/include $(pkgincludedir) +else +library_includedir = $(pkgincludedir) +endif c_sources = ipa_nat_drv.c \ ipa_nat_drvi.c \ ipa_nat_logi.c -library_includedir = $(pkgincludedir) library_include_HEADERS = ./../inc/ipa_nat_drvi.h \ ./../inc/ipa_nat_drv.h \ ./../inc/ipa_nat_logi.h +if KERNELMODULES +noinst_LIBRARIES = libipanat.a +libipanat_a_C = @C@ +libipanat_a_SOURCES = $(c_sources) +else lib_LTLIBRARIES = libipanat.la libipanat_la_C = @C@ libipanat_la_SOURCES = $(c_sources) libipanat_la_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) libipanat_la_LDFLAGS = -shared $(common_LDFLAGS) -version-info 1:0:0 +endif diff --git a/ipanat/src/ipa_nat_drv.c b/ipanat/src/ipa_nat_drv.c index 66504e1..d01a6c9 100644 --- a/ipanat/src/ipa_nat_drv.c +++ b/ipanat/src/ipa_nat_drv.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2013, The Linux Foundation. All rights reserved. +Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -173,3 +173,43 @@ int ipa_nat_query_timestamp(uint32_t tbl_hdl, } +/** +* ipa_nat_modify_pdn() - modify single PDN entry in the PDN config table +* @table_handle: [in] handle of ipv4 nat table +* @pdn_index : [in] the index of the entry to be modified +* @pdn_info : [in] values for the PDN entry to be changed +* +* Modify a PDN entry +* +* Returns: 0 On Success, negative on failure +*/ +int ipa_nat_modify_pdn(uint32_t tbl_hdl, + uint8_t pdn_index, + ipa_nat_pdn_entry *pdn_info) +{ + struct ipa_ioc_nat_pdn_entry pdn_data; + + if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS) { + IPAERR("invalid parameters passed \n"); + return -EINVAL; + } + + if (!pdn_info) { + IPAERR("pdn_info is NULL \n"); + return -EINVAL; + } + + if (pdn_index > IPA_MAX_PDN_NUM) { + IPAERR("PDN index is out of range %d", pdn_index); + return -EINVAL; + } + + pdn_data.pdn_index = pdn_index; + pdn_data.public_ip = pdn_info->public_ip; + pdn_data.src_metadata = pdn_info->src_metadata; + pdn_data.dst_metadata = pdn_info->dst_metadata; + + return ipa_nati_modify_pdn(&pdn_data); +} + + diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c index 9b96c44..d309bb3 100644 --- a/ipanat/src/ipa_nat_drvi.c +++ b/ipanat/src/ipa_nat_drvi.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2013, The Linux Foundation. All rights reserved. +Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -33,11 +33,21 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef USE_GLIB #include <glib.h> #define strlcpy g_strlcpy +#else +static size_t strlcpy(char * dst, const char * src, size_t size) { + if (size < 1) + return 0; + strncpy(dst, src, size - 1); + dst[size - 1] = 0; + return strlen(dst); +} #endif struct ipa_nat_cache ipv4_nat_cache; pthread_mutex_t nat_mutex = PTHREAD_MUTEX_INITIALIZER; +static ipa_nat_pdn_entry pdns[IPA_MAX_PDN_NUM]; + /* ------------------------------------------ UTILITY FUNCTIONS START --------------------------------------------*/ @@ -153,6 +163,26 @@ uint32_t Read32BitFieldValue(uint32_t param, } } +/** +* GetIPAVer(void) - store IPA HW ver in cache +* +* +* Returns: 0 on success, negative on failure +*/ +int GetIPAVer(void) +{ + int ret; + + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_HW_VERSION, &ipv4_nat_cache.ver); + if (ret != 0) { + perror("GetIPAVer(): ioctl error value"); + IPAERR("unable to get IPA version. Error ;%d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EINVAL; + } + IPADBG("IPA version is %d\n", ipv4_nat_cache.ver); + return 0; +} /** * CreateNatDevice() - Create nat devices @@ -248,6 +278,7 @@ void GetNearestEven(uint16_t num, uint16_t *ret) /** * dst_hash() - Find the index into ipv4 base table + * @public_ip: [in] public_ip * @trgt_ip: [in] Target IP address * @trgt_port: [in] Target port * @public_port: [in] Public port @@ -261,13 +292,18 @@ void GetNearestEven(uint16_t num, uint16_t *ret) * * Returns: >0 index into ipv4 base table, negative on failure */ -static uint16_t dst_hash(uint32_t trgt_ip, uint16_t trgt_port, - uint16_t public_port, uint8_t proto, - uint16_t size) +static uint16_t dst_hash(uint32_t public_ip, uint32_t trgt_ip, + uint16_t trgt_port, uint16_t public_port, + uint8_t proto, uint16_t size) { uint16_t hash = ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip >> 16)) ^ (trgt_port) ^ (public_port) ^ (proto); + if (ipv4_nat_cache.ver >= IPA_HW_v4_0) + hash ^= ((uint16_t)(public_ip)) ^ + ((uint16_t)(public_ip >> 16)); + + IPADBG("public ip 0x%X\n", public_ip); IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port); IPADBG("public_port: 0x%x\n", public_port); IPADBG("proto: 0x%x size: 0x%x\n", proto, size); @@ -682,6 +718,12 @@ int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr, return -EINVAL; } + /* store the initial public ip address in the cached pdn table + this is backward compatible for pre IPAv4 versions, we will always + use this ip as the single PDN address + */ + pdns[0].public_ip = public_ip_addr; + /* Return table handle */ ipv4_nat_cache.table_cnt++; *tbl_hdl = ipv4_nat_cache.table_cnt; @@ -734,6 +776,11 @@ int ipa_nati_alloc_table(uint16_t number_of_entries, ipv4_nat_cache.ipa_fd = fd; } + if (GetIPAVer()) { + IPAERR("unable to get ipa ver\n"); + return -EIO; + } + ret = CreateNatDevice(mem); return ret; } @@ -1014,6 +1061,30 @@ int ipa_nati_query_timestamp(uint32_t tbl_hdl, return 0; } +int ipa_nati_modify_pdn(struct ipa_ioc_nat_pdn_entry *entry) +{ + if (entry->public_ip == 0) + IPADBG("PDN %d public ip will be set to 0\n", entry->pdn_index); + + if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_MODIFY_PDN, entry)) { + perror("ipa_nati_modify_pdn(): ioctl error value"); + IPAERR("unable to call modify pdn icotl\n"); + IPAERR("index %d, ip 0x%X, src_metdata 0x%X, dst_metadata 0x%X\n", + entry->pdn_index, entry->public_ip, entry->src_metadata, entry->dst_metadata); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EIO; + } + + pdns[entry->pdn_index].public_ip = entry->public_ip; + pdns[entry->pdn_index].dst_metadata = entry->dst_metadata; + pdns[entry->pdn_index].src_metadata = entry->src_metadata; + + IPADBG("posted IPA_IOC_NAT_MODIFY_PDN to kernel successfully and stored in cache\n index %d, ip 0x%X, src_metdata 0x%X, dst_metadata 0x%X\n", + entry->pdn_index, entry->public_ip, entry->src_metadata, entry->dst_metadata); + + return 0; +} + int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl, const ipa_nat_ipv4_rule *clnt_rule, uint32_t *rule_hdl) @@ -1023,6 +1094,14 @@ int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl, struct ipa_nat_indx_tbl_sw_rule index_sw_rule; uint16_t new_entry, new_index_tbl_entry; + /* verify that the rule's PDN is valid */ + if (clnt_rule->pdn_index >= IPA_MAX_PDN_NUM || + pdns[clnt_rule->pdn_index].public_ip == 0) { + IPAERR("invalid parameters, pdn index %d, public ip = 0x%X\n", + clnt_rule->pdn_index, pdns[clnt_rule->pdn_index].public_ip); + return -EINVAL; + } + memset(&sw_rule, 0, sizeof(sw_rule)); memset(&index_sw_rule, 0, sizeof(index_sw_rule)); @@ -1114,7 +1193,7 @@ uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule, uint16_t prev = 0, nxt_indx = 0, new_entry; struct ipa_nat_rule *tbl = NULL, *expn_tbl = NULL; - pub_ip_addr = tbl_ptr->public_addr; + pub_ip_addr = pdns[clnt_rule->pdn_index].public_ip; tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_rules_addr; expn_tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_expn_rules_addr; @@ -1126,6 +1205,7 @@ uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule, sw_rule->public_port = clnt_rule->public_port; sw_rule->target_ip = clnt_rule->target_ip; sw_rule->target_port = clnt_rule->target_port; + sw_rule->pdn_index = clnt_rule->pdn_index; /* consider only public and private ip fields */ sw_rule->ip_chksum = ipa_nati_calc_ip_cksum(pub_ip_addr, @@ -1152,10 +1232,11 @@ uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule, */ sw_rule->time_stamp = 0; sw_rule->rsvd2 = 0; + sw_rule->rsvd3 = 0; sw_rule->prev_index = 0; sw_rule->indx_tbl_entry = 0; - new_entry = dst_hash(clnt_rule->target_ip, + new_entry = dst_hash(pub_ip_addr, clnt_rule->target_ip, clnt_rule->target_port, clnt_rule->public_port, clnt_rule->protocol, |