From patchwork Mon Mar 12 17:25:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jasvinder Singh X-Patchwork-Id: 35995 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B63CE5F14; Mon, 12 Mar 2018 18:52:12 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id B4A262BA5 for ; Mon, 12 Mar 2018 18:52:06 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 12 Mar 2018 10:26:24 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,462,1515484800"; d="scan'208";a="182012815" Received: from silpixa00381635.ir.intel.com (HELO silpixa00381635.ger.corp.intel.com) ([10.237.222.149]) by orsmga004.jf.intel.com with ESMTP; 12 Mar 2018 10:26:24 -0700 From: Jasvinder Singh To: dev@dpdk.org Cc: cristian.dumitrescu@intel.com Date: Mon, 12 Mar 2018 17:25:37 +0000 Message-Id: <20180312172615.6621-7-jasvinder.singh@intel.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20180312172615.6621-1-jasvinder.singh@intel.com> References: <20180309182426.135278-2-jasvinder.singh@intel.com> <20180312172615.6621-1-jasvinder.singh@intel.com> Subject: [dpdk-dev] [PATCH v2 06/44] pipeline: add nat action X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add implementation of Network Address Translation(NAT) action. Signed-off-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_table_action.c | 162 +++++++++++++++++++++++++++++++++ lib/librte_pipeline/rte_table_action.h | 39 ++++++++ 2 files changed, 201 insertions(+) diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c index cd8e7d1..ddffe18 100644 --- a/lib/librte_pipeline/rte_table_action.c +++ b/lib/librte_pipeline/rte_table_action.c @@ -733,6 +733,115 @@ pkt_work_encap(struct rte_mbuf *mbuf, } /** + * RTE_TABLE_ACTION_NAT + */ +static int +nat_cfg_check(struct rte_table_action_nat_config *nat) +{ + if ((nat->proto != 0x06) && + (nat->proto != 0x11)) + return -ENOTSUP; + + return 0; +} + +struct nat_ipv4_data { + uint32_t addr; + uint16_t port; + uint16_t checksum; +} __attribute__((__packed__)); + +struct nat_ipv6_data { + uint8_t addr[16]; + uint16_t port; + uint16_t checksum; +} __attribute__((__packed__)); + +static size_t +nat_data_size(struct rte_table_action_nat_config *nat __rte_unused, + struct rte_table_action_common_config *common) +{ + int ip_version = common->ip_version; + + return (ip_version) ? + sizeof(struct nat_ipv4_data) : + sizeof(struct nat_ipv6_data); +} + +static int +nat_apply_check(struct rte_table_action_nat_params *p, + struct rte_table_action_common_config *cfg) +{ + if ((p->ip_version && (cfg->ip_version == 0)) || + ((p->ip_version == 0) && cfg->ip_version)) + return -EINVAL; + + return 0; +} + +static int +nat_apply(void *data, + struct rte_table_action_nat_params *p, + struct rte_table_action_common_config *cfg) +{ + int status; + + /* Check input arguments */ + status = nat_apply_check(p, cfg); + if (status) + return status; + + /* Apply */ + if (p->ip_version) { + struct nat_ipv4_data *d = data; + + d->addr = rte_htonl(p->addr.ipv4); + d->port = rte_htons(p->port); + d->checksum = 0; + } else { + struct nat_ipv6_data *d = data; + + memcpy(d->addr, p->addr.ipv6, sizeof(d->addr)); + d->port = rte_htons(p->port); + d->checksum = 0; + } + + return 0; +} + +static __rte_always_inline void +pkt_ipv4_work_nat(struct ipv4_hdr *ip, + struct nat_ipv4_data *data, + struct rte_table_action_nat_config *cfg) +{ + struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1]; + + if (cfg->source_nat) { + ip->src_addr = data->addr; + tcp->src_port = data->port; + } else { + ip->dst_addr = data->addr; + tcp->dst_port = data->port; + } +} + +static __rte_always_inline void +pkt_ipv6_work_nat(struct ipv6_hdr *ip, + struct nat_ipv6_data *data, + struct rte_table_action_nat_config *cfg) +{ + struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1]; + + if (cfg->source_nat) { + rte_memcpy(ip->src_addr, data->addr, 16); + tcp->src_port = data->port; + } else { + rte_memcpy(ip->dst_addr, data->addr, 16); + tcp->dst_port = data->port; + } +} + +/** * Action profile */ static int @@ -743,6 +852,7 @@ action_valid(enum rte_table_action_type action) case RTE_TABLE_ACTION_MTR: case RTE_TABLE_ACTION_TM: case RTE_TABLE_ACTION_ENCAP: + case RTE_TABLE_ACTION_NAT: return 1; default: return 0; @@ -758,6 +868,7 @@ struct ap_config { struct rte_table_action_mtr_config mtr; struct rte_table_action_tm_config tm; struct rte_table_action_encap_config encap; + struct rte_table_action_nat_config nat; }; static size_t @@ -770,6 +881,8 @@ action_cfg_size(enum rte_table_action_type action) return sizeof(struct rte_table_action_tm_config); case RTE_TABLE_ACTION_ENCAP: return sizeof(struct rte_table_action_encap_config); + case RTE_TABLE_ACTION_NAT: + return sizeof(struct rte_table_action_nat_config); default: return 0; } @@ -789,6 +902,9 @@ action_cfg_get(struct ap_config *ap_config, case RTE_TABLE_ACTION_ENCAP: return &ap_config->encap; + case RTE_TABLE_ACTION_NAT: + return &ap_config->nat; + default: return NULL; } @@ -829,6 +945,10 @@ action_data_size(enum rte_table_action_type action, case RTE_TABLE_ACTION_ENCAP: return encap_data_size(&ap_config->encap); + case RTE_TABLE_ACTION_NAT: + return nat_data_size(&ap_config->nat, + &ap_config->common); + default: return 0; } @@ -911,6 +1031,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil status = encap_cfg_check(action_config); break; + case RTE_TABLE_ACTION_NAT: + status = nat_cfg_check(action_config); + break; + default: status = 0; break; @@ -1039,6 +1163,11 @@ rte_table_action_apply(struct rte_table_action *action, &action->cfg.encap, &action->cfg.common); + case RTE_TABLE_ACTION_NAT: + return nat_apply(action_data, + action_params, + &action->cfg.common); + default: return -EINVAL; } @@ -1268,6 +1397,16 @@ pkt_work(struct rte_mbuf *mbuf, ip_offset); } + if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { + void *data = + action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT); + + if (cfg->common.ip_version) + pkt_ipv4_work_nat(ip, data, &cfg->nat); + else + pkt_ipv6_work_nat(ip, data, &cfg->nat); + } + return drop_mask; } @@ -1451,6 +1590,29 @@ pkt4_work(struct rte_mbuf **mbufs, ip_offset); } + if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) { + void *data0 = + action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT); + void *data1 = + action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT); + void *data2 = + action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT); + void *data3 = + action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT); + + if (cfg->common.ip_version) { + pkt_ipv4_work_nat(ip0, data0, &cfg->nat); + pkt_ipv4_work_nat(ip1, data1, &cfg->nat); + pkt_ipv4_work_nat(ip2, data2, &cfg->nat); + pkt_ipv4_work_nat(ip3, data3, &cfg->nat); + } else { + pkt_ipv6_work_nat(ip0, data0, &cfg->nat); + pkt_ipv6_work_nat(ip1, data1, &cfg->nat); + pkt_ipv6_work_nat(ip2, data2, &cfg->nat); + pkt_ipv6_work_nat(ip3, data3, &cfg->nat); + } + } + return drop_mask0 | (drop_mask1 << 1) | (drop_mask2 << 2) | diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h index c5c987d..5204511 100644 --- a/lib/librte_pipeline/rte_table_action.h +++ b/lib/librte_pipeline/rte_table_action.h @@ -77,6 +77,9 @@ enum rte_table_action_type { /** Packet encapsulations. */ RTE_TABLE_ACTION_ENCAP, + + /** Network Address Translation (NAT). */ + RTE_TABLE_ACTION_NAT, }; /** Common action configuration (per table action profile). */ @@ -409,6 +412,42 @@ struct rte_table_action_encap_params { }; /** + * RTE_TABLE_ACTION_NAT + */ +/** NAT action configuration (per table action profile). */ +struct rte_table_action_nat_config { + /** When non-zero, the IP source address and L4 protocol source port are + * translated. When zero, the IP destination address and L4 protocol + * destination port are translated. + */ + int source_nat; + + /** Layer 4 protocol, for example TCP (0x06) or UDP (0x11). The checksum + * field is computed differently and placed at different header offset + * by each layer 4 protocol. + */ + uint8_t proto; +}; + +/** NAT action parameters (per table rule). */ +struct rte_table_action_nat_params { + /** IP version for *addr*: non-zero for IPv4, zero for IPv6. */ + int ip_version; + + /** IP address. */ + union { + /** IPv4 address; only valid when *ip_version* is non-zero. */ + uint32_t ipv4; + + /** IPv6 address; only valid when *ip_version* is set to 0. */ + uint8_t ipv6[16]; + } addr; + + /** Port. */ + uint16_t port; +}; + +/** * Table action profile. */ struct rte_table_action_profile;