From patchwork Fri Mar 9 18:23:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jasvinder Singh X-Patchwork-Id: 35885 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 4F3D96D85; Fri, 9 Mar 2018 19:24:37 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id F066F5F6C for ; Fri, 9 Mar 2018 19:24:33 +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 orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Mar 2018 10:24:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,446,1515484800"; d="scan'208";a="181382216" Received: from silpixa00381635.ir.intel.com (HELO silpixa00381635.ger.corp.intel.com) ([10.237.222.149]) by orsmga004.jf.intel.com with ESMTP; 09 Mar 2018 10:24:33 -0800 From: Jasvinder Singh To: dev@dpdk.org Cc: cristian.dumitrescu@intel.com Date: Fri, 9 Mar 2018 18:23:55 +0000 Message-Id: <20180309182426.135278-7-jasvinder.singh@intel.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20180309182426.135278-1-jasvinder.singh@intel.com> References: <20180309182426.135278-1-jasvinder.singh@intel.com> Subject: [dpdk-dev] [PATCH 06/37] 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 a3c1546..fccf577 100644 --- a/lib/librte_pipeline/rte_table_action.c +++ b/lib/librte_pipeline/rte_table_action.c @@ -731,6 +731,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 @@ -741,6 +850,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; @@ -756,6 +866,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 @@ -768,6 +879,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; } @@ -787,6 +900,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; } @@ -827,6 +943,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; } @@ -909,6 +1029,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; @@ -1037,6 +1161,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; } @@ -1266,6 +1395,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; } @@ -1449,6 +1588,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;