summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmir Levy <alevy@codeaurora.org>2017-07-03 10:51:22 +0300
committerGerrit - the friendly Code Review server <code-review@localhost>2017-07-08 23:43:13 -0700
commitdfda87d642c35b9185081a837182a9cc182dd0f7 (patch)
treef261e5b3440741b1538cb9266c519b5a1a9cef1a
parent1d6dbdcef40b4f22303183cdc7c178594f8ecd0a (diff)
downloadipacfg-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
-rw-r--r--configure.ac1
-rw-r--r--ipacm/src/IPACM_Conntrack_NATApp.cpp1
-rw-r--r--ipanat/inc/ipa_nat_drv.h30
-rw-r--r--ipanat/inc/ipa_nat_drvi.h38
-rw-r--r--ipanat/src/Makefile.am19
-rw-r--r--ipanat/src/ipa_nat_drv.c42
-rw-r--r--ipanat/src/ipa_nat_drvi.c93
7 files changed, 209 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac
index 33164c0..6662ef6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,7 @@ AC_ARG_WITH(sanitized-headers,
AS_HELP_STRING([--with-sanitized-headers=DIR],
[Specify the location of the sanitized Linux headers]),
[CPPFLAGS="$CPPFLAGS -idirafter $withval"])
+AM_CONDITIONAL(KERNELMODULES, [test -n -eq 0])
AC_ARG_WITH([glib],
AC_HELP_STRING([--with-glib],
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index 2c06642..077cab5 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -344,6 +344,7 @@ int NatApp::AddEntry(const nat_table_entry *rule)
}
else
{
+ memset(&nat_rule, 0, sizeof(nat_rule));
nat_rule.private_ip = rule->private_ip;
nat_rule.target_ip = rule->target_ip;
nat_rule.target_port = rule->target_port;
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,