2 // Copyright (c) 2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include "cgnapt_pcp_be.h"
19 #include "pipeline_cgnapt_be.h"
20 #include "pipeline_cgnapt_common.h"
24 * Pipeline CG-NAPT PCP BE Implementation.
26 * Implementation of Pipeline CG-NAPT PCP Back End (BE).
27 * Handles PCP requests for both IPv4 & IPv6
28 * Constructs PCP responses for both IPv4 & IPv6
29 * Provides backend CLI support.
30 * Runs on CGNAPT pipeline core
37 uint32_t pcp_lifetime = 60;
38 uint8_t pcp_ipv4_format[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
41 * Function to initialize PCP stuff
44 enum PCP_RET pcp_init(void)
46 /* Init of PCP mempool */
49 pcp_mbuf_pool = rte_pktmbuf_pool_create(
50 "pcp_mbuf_pool", 64, 32, 0,
51 RTE_MBUF_DEFAULT_BUF_SIZE,
54 if (pcp_mbuf_pool == NULL) {
55 printf("PCP mbuf pool creation failed\n");
56 return PCP_INIT_UNSUCCESS;
59 printf("In pcp_init: success\n");
60 return PCP_INIT_SUCCESS;
64 * Function to handle PCP CLI commands
67 * Pipieline struct associated with each pipeline
69 * CLI message enqueued by master thread
72 void *pipeline_cgnapt_msg_req_pcp_handler(
73 __rte_unused struct pipeline *p,
77 struct pipeline_cgnapt_pcp_msg_rsp *rsp = msg;
78 struct pipeline_cgnapt_pcp_msg_req *req = msg;
82 if (req->cmd == CGNAPT_PCP_CMD_STATS) {
83 printf("pcp_success_count:%d\n", pcp_success_count);
84 printf("pcp_error_count:%d\n", pcp_error_count);
85 printf("pcp_entry_count:%d\n", pcp_entry_count);
89 if (req->cmd == CGNAPT_PCP_CMD_PCP_ENABLE) {
92 printf("PCP option is enabled\n");
95 printf("PCP option is disabled\n");
99 if (req->cmd == CGNAPT_PCP_CMD_SET_LIFETIME) {
100 pcp_lifetime = req->lifetime;
101 printf("pcp_lifetime:%" PRIu32 "\n", pcp_lifetime);
104 if (req->cmd == CGNAPT_PCP_CMD_GET_LIFETIME) {
105 printf("pcp_lifetime:%" PRIu32 "\n", pcp_lifetime);
109 printf("CG-NAPT PCP handler called with wrong args %x %x\n",
110 req->cmd, req->lifetime);
116 struct rte_mbuf *rx_pkt,
117 struct rte_mbuf *tx_pkt);
120 * Function to copy Rx pkt data to Tx pkt data
125 * Transmitting PCP pkt
129 struct rte_mbuf *rx_pkt,
130 struct rte_mbuf *tx_pkt)
135 buf1 = rte_pktmbuf_mtod(rx_pkt, char *);
136 buf2 = rte_pktmbuf_append(tx_pkt, rx_pkt->data_len);
138 rte_memcpy(buf2, buf1, rx_pkt->data_len);
142 * Function to construct L2,L3,L4 in pkt and to send out
147 * Transmitting PCP pkt
149 * Version of pkt : IPv4 or IPv6
151 * A pointer to struct rte_pipeline
154 void construct_pcp_resp(
155 struct rte_mbuf *rx_pkt,
156 struct rte_mbuf *tx_pkt,
157 uint8_t ver, struct rte_pipeline *rte_p)
159 struct ether_hdr *eth_tx, *eth_rx;
160 struct ipv4_hdr *ipv4_tx, *ipv4_rx;
161 struct ipv6_hdr *ipv6_tx, *ipv6_rx;
162 struct udp_hdr *udp_tx, *udp_rx;
163 struct pcp_resp_hdr *pcp_resp;
164 struct pcp_req_hdr *pcp_req;
166 tx_pkt->port = rx_pkt->port;
169 pcp_req = (struct pcp_req_hdr *)
170 ((uint8_t *) rx_pkt + IPV4_PCP_OFST);
171 pcp_resp = (struct pcp_resp_hdr *)
172 ((uint8_t *) tx_pkt + IPV4_PCP_OFST);
174 pcp_req = (struct pcp_req_hdr *)
175 ((uint8_t *) rx_pkt + IPV6_PCP_OFST);
176 pcp_resp = (struct pcp_resp_hdr *)
177 ((uint8_t *) tx_pkt + IPV6_PCP_OFST);
180 if (pcp_resp->result_code == PCP_SUCCESS) {
181 memset(pcp_resp->reserve, 0, 12);
184 memcpy(pcp_resp->reserve, &pcp_req->cli_ip[1], 12);
188 pcp_resp->req_resp = PCP_RESP;
189 pcp_resp->res_unuse = 0x00;
191 pcp_resp->epoch_time = rte_bswap32(time(NULL));
193 /* swap L2 identities */
194 eth_rx = rte_pktmbuf_mtod(rx_pkt, struct ether_hdr *);
195 eth_tx = rte_pktmbuf_mtod(tx_pkt, struct ether_hdr *);
197 memcpy(ð_tx->s_addr, ð_rx->d_addr, sizeof(struct ether_addr));
198 memcpy(ð_tx->d_addr, ð_rx->s_addr, sizeof(struct ether_addr));
200 /* swap L3 identities */
203 ipv4_rx = (struct ipv4_hdr *)((uint8_t *) rx_pkt + IP_OFFSET);
204 udp_rx = (struct udp_hdr *)((uint8_t *) rx_pkt + IPV4_UDP_OFST);
206 ipv4_tx = (struct ipv4_hdr *)((uint8_t *) tx_pkt + IP_OFFSET);
207 udp_tx = (struct udp_hdr *)((uint8_t *) tx_pkt + IPV4_UDP_OFST);
209 ipv4_tx->src_addr = ipv4_rx->dst_addr;
210 ipv4_tx->dst_addr = ipv4_rx->src_addr;
212 /* swap L4 identities */
214 udp_tx->src_port = udp_rx->dst_port;
215 udp_tx->dst_port = udp_rx->src_port;
216 udp_tx->dgram_cksum = 0;
217 udp_tx->dgram_cksum =
218 rte_ipv4_udptcp_cksum(ipv4_tx, (void *)udp_tx);
220 ipv4_tx->total_length =
221 rte_cpu_to_be_16(pcp_resp->result_code ==
222 PCP_MAP ? IPV4_PCP_MAP_PL_LEN :
223 IPV4_PCP_PEER_PL_LEN);
225 ipv4_tx->packet_id = 0xaabb;
226 ipv4_tx->fragment_offset = 0x0000;
227 ipv4_tx->time_to_live = 64;
228 ipv4_tx->next_proto_id = IP_PROTOCOL_UDP;
229 ipv4_tx->hdr_checksum = 0;
230 ipv4_tx->hdr_checksum = rte_ipv4_cksum(ipv4_tx);
233 ipv6_rx = (struct ipv6_hdr *)((uint8_t *) rx_pkt + IP_OFFSET);
234 udp_rx = (struct udp_hdr *)((uint8_t *) rx_pkt + IPV6_UDP_OFST);
236 ipv6_tx = (struct ipv6_hdr *)((uint8_t *) tx_pkt + IP_OFFSET);
237 udp_tx = (struct udp_hdr *)((uint8_t *) tx_pkt + IPV6_UDP_OFST);
239 memcpy((uint8_t *)&ipv6_tx->src_addr[0],
240 (uint8_t *)&ipv6_rx->dst_addr[0], 16);
241 memcpy((uint8_t *)&ipv6_tx->dst_addr[0],
242 (uint8_t *)&ipv6_rx->src_addr[0], 16);
244 /* swap L4 identities */
246 udp_tx->src_port = udp_rx->dst_port;
247 udp_tx->dst_port = udp_rx->src_port;
249 udp_tx->dgram_cksum = 0;
250 udp_tx->dgram_cksum =
251 rte_ipv6_udptcp_cksum(ipv6_tx, (void *)udp_tx);
252 ipv6_tx->payload_len =
253 rte_cpu_to_be_16(pcp_resp->result_code ==
254 PCP_MAP ? IPV6_PCP_MAP_PL_LEN :
255 IPV6_PCP_PEER_PL_LEN);
257 ipv6_tx->proto = IP_PROTOCOL_UDP;
258 ipv6_tx->hop_limits = 64;
262 rte_hexdump(stdout, "Transferring PCP Pkt", tx_pkt, 400);
265 rte_pipeline_port_out_packet_insert(rte_p, tx_pkt->port, tx_pkt);
269 * Function to handle PCP requests
274 * Version of pkt : IPv4 or IPv6
276 * A pointer to struct pipeline_cgnapt
279 void handle_pcp_req(struct rte_mbuf *rx_pkt,
281 void *pipeline_cgnapt_ptr)
283 struct ipv4_hdr *ipv4 = NULL;
284 struct ipv6_hdr *ipv6 = NULL;
285 struct udp_hdr *udp_rx = NULL;
286 struct pcp_req_hdr *pcp_req = NULL;
287 struct pcp_resp_hdr *pcp_resp = NULL;
288 struct rte_mbuf *tx_pkt = NULL;
289 struct pipeline_cgnapt *p_nat = pipeline_cgnapt_ptr;
291 if (pcp_mbuf_pool == NULL)
292 printf("handle PCP: PCP pool is NULL\n");
293 tx_pkt = rte_pktmbuf_alloc(pcp_mbuf_pool);
294 if (tx_pkt == NULL) {
295 printf("unable to allocate mem from PCP pool\n");
300 clone_data(rx_pkt, tx_pkt);
303 rte_hexdump(stdout, "cloned PCP Pkt", tx_pkt, 400);
307 pcp_req = (struct pcp_req_hdr *)
308 ((uint8_t *) rx_pkt + IPV4_PCP_OFST);
309 pcp_resp = (struct pcp_resp_hdr *)
310 ((uint8_t *) tx_pkt + IPV4_PCP_OFST);
311 udp_rx = (struct udp_hdr *)
312 ((uint8_t *) rx_pkt + IPV4_UDP_OFST);
314 pcp_req = (struct pcp_req_hdr *)
315 ((uint8_t *) rx_pkt + IPV6_PCP_OFST);
316 pcp_resp = (struct pcp_resp_hdr *)
317 ((uint8_t *) tx_pkt + IPV6_PCP_OFST);
318 udp_rx = (struct udp_hdr *)
319 ((uint8_t *) rx_pkt + IPV6_UDP_OFST);
322 /* Check for all conditions to drop the packet */
324 /* Check the PCP version */
326 if (pcp_req->ver != 2) {
328 printf("PCP version mismatch\n");
330 pcp_resp->result_code = PCP_UNSUPP_VERSION;
331 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
332 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
336 /* If req msg is less than 2 octects */
338 if (rte_bswap16(udp_rx->dgram_len) > 1100) {
340 printf("PCP len > 1000\n");
342 pcp_resp->result_code = PCP_MALFORMED_REQUEST;
343 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
344 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
348 /* Silently drop the response pkt */
349 if (pcp_req->req_resp == PCP_RESP) {
351 printf("Its PCP Resp\n");
356 /* Check for supported PCP opcode */
358 if ((pcp_req->opcode != PCP_MAP) && (pcp_req->opcode != PCP_PEER)) {
360 printf("Neither PCP_MAP not PCP_PEER\n");
362 pcp_resp->result_code = PCP_UNSUPP_OPCODE;
363 printf("result code:%d\n", PCP_UNSUPP_OPCODE);
364 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
365 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
369 /* To check whether options are using in PCP */
373 (uint8_t *) ((uint8_t *) udp_rx + PCP_REQ_RESP_HDR_SZ +
374 PCP_MAP_REQ_RESP_SZ);
377 printf("No PCP option support\n");
379 pcp_resp->result_code = PCP_UNSUPP_OPTION;
380 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
381 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
387 ipv4 = (struct ipv4_hdr *)((uint8_t *) rx_pkt + IP_OFFSET);
388 /* Check whether 3rd party host is requesting */
389 if (ipv4->src_addr != pcp_req->cli_ip[3]) {
392 printf("PCP client IP & req IP mismatch\n");
395 printf("src addr:%x req addr:%x\n", ipv4->src_addr,
398 pcp_resp->result_code = PCP_ADDRESS_MISMATCH;
399 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
400 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
405 ipv6 = (struct ipv6_hdr *)((uint8_t *) rx_pkt + IP_OFFSET);
406 /* 5. Check whether 3rd party host is requesting */
407 if (memcmp(ipv6->src_addr, pcp_req->cli_ip, IPV6_SZ) != 0) {
409 printf("PCP client IP & req IP mismatch\n");
412 pcp_resp->result_code = PCP_ADDRESS_MISMATCH;
413 pcp_resp->life_time = rte_bswap32(PCP_LONG_LTIME);
414 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
419 struct pipeline_cgnapt_entry_key key;
420 memset(&key, 0, sizeof(struct pipeline_cgnapt_entry_key));
423 switch (pcp_req->opcode) {
427 struct pcp_map_req *map_req;
428 struct pcp_map_resp *map_resp;
430 /* Not a PCP MAP Request(36) */
432 if ((rte_be_to_cpu_16(udp_rx->dgram_len) -
433 sizeof(struct pcp_req_hdr)) <= 35)
437 map_req = (struct pcp_map_req *)
438 ((uint8_t *) rx_pkt +
440 map_resp = (struct pcp_map_resp *)
441 ((uint8_t *) tx_pkt +
444 map_req = (struct pcp_map_req *)
445 ((uint8_t *) rx_pkt +
447 map_resp = (struct pcp_map_resp *)
448 ((uint8_t *) tx_pkt +
452 /* 4. Check for supported protocol */
454 if (map_req->protocol != IP_PROTOCOL_TCP &&
455 map_req->protocol != IP_PROTOCOL_UDP) {
457 printf("PCP Req is neither TCP nor "
461 pcp_resp->result_code = PCP_UNSUPP_PROTOCOL;
462 pcp_resp->life_time =
463 rte_bswap32(PCP_LONG_LTIME);
464 construct_pcp_resp(rx_pkt, tx_pkt,
469 /* Preparing key to search the entry */
471 key.pid = rx_pkt->port;
472 key.ip = rte_bswap32(pcp_req->cli_ip[3]);
473 key.port = rte_bswap16(map_req->int_port);
475 #ifdef NAT_ONLY_CONFIG_REQ
476 if (nat_only_config_flag)
481 rte_hexdump(stdout, "key", &key,
482 sizeof(struct pipeline_cgnapt_entry_key));
485 pos = rte_hash_lookup(napt_common_table, &key);
487 /* PCP request for deleting the CGNAPT entry */
488 if (rte_bswap32(pcp_req->life_time) == 0) {
490 if (pos != -ENOENT) {
492 long long int time_out;
494 napt_hash_tbl_entries[pos].
497 /* Check for PCP entry first */
500 (napt_common_table, &key);
501 pcp_resp->life_time = 0;
502 pcp_resp->result_code =
504 memset(pcp_resp->reserve, 0, 12);
506 printf("PCP SUCCESS : PCP MAP req for "
510 construct_pcp_resp(rx_pkt, tx_pkt,
517 if (time_out == STATIC_CGNAPT_TIMEOUT)
518 pcp_resp->life_time = 0xffffffff;
519 else if (time_out == DYNAMIC_CGNAPT_TIMEOUT)
520 pcp_resp->life_time =
521 rte_bswap32(PCP_LONG_LTIME);
523 pcp_resp->result_code = PCP_NOT_AUTHORIZED;
526 printf("PCP Failed : Not a PCP request "
530 construct_pcp_resp(rx_pkt, tx_pkt,
535 pcp_resp->life_time = 0;
536 pcp_resp->result_code = PCP_SUCCESS;
537 memset(pcp_resp->reserve, 0, 12);
540 printf("PCP SUCCESS : MAP req entry not "
541 "found for deletion\n");
544 construct_pcp_resp(rx_pkt, tx_pkt,
550 /* PCP request for adding the CGNAPT entry */
551 struct cgnapt_table_entry *entry = NULL;
553 if ((pos == -ENOENT)) {
555 entry = add_dynamic_cgnapt_entry(&p_nat->p,
557 rte_bswap32(pcp_req->life_time) <=
559 rte_bswap32(pcp_req->life_time):
564 ipv6->src_addr, &err);
565 /* Ignore klocwork issue in above calling */
567 /* MAP Err : unable to allocate
568 * requested resources
573 printf("PCP Failure : unable to "
574 "create PCP req entry\n");
577 pcp_resp->result_code =
579 pcp_resp->life_time =
580 rte_bswap32(PCP_SHORT_LTIME);
581 construct_pcp_resp(rx_pkt, tx_pkt,
586 printf("PCP dynamic entry created "
592 /* Check whether PCP request created
595 if (napt_hash_tbl_entries[pos].data.
598 napt_hash_tbl_entries[pos].
599 data.timeout = pcp_lifetime;
601 struct cgnapt_table_entry *p_entry, *s_entry;
602 struct pipeline_cgnapt_entry_key s_key;
604 p_entry = &napt_hash_tbl_entries[pos];
605 entry = &napt_hash_tbl_entries[pos];
606 s_key.port = napt_hash_tbl_entries[pos].
608 s_key.ip = napt_hash_tbl_entries[pos].
610 s_key.pid = napt_hash_tbl_entries[pos].
613 /* Getting ingress or second entry
617 pos = rte_hash_lookup(napt_common_table,
619 s_entry = &napt_hash_tbl_entries[pos];
621 /* Enqueue the info to
624 timer_thread_enqueue(&key, &s_key,
626 (struct pipeline *)p_nat);
630 if (!napt_hash_tbl_entries[pos].
632 pcp_resp->life_time =
633 rte_bswap32(PCP_LONG_LTIME);
634 else // if static entry
635 pcp_resp->life_time =
638 pcp_resp->result_code =
642 printf("PCP Failure : Not authorized "
643 "to delete entry\n");
644 printf("Not a PCP request "
647 construct_pcp_resp(rx_pkt, tx_pkt,
654 /* Fill PCP Resp fields */
655 pcp_resp->result_code = PCP_SUCCESS;
657 rte_bswap32(pcp_req->life_time) < pcp_lifetime?
658 (pcp_resp->life_time = pcp_req->life_time):
659 (pcp_resp->life_time = rte_bswap32(pcp_lifetime));
661 /* Fill PCP MAP Resp fields */
662 memcpy(map_resp->nonce, map_req->nonce, 12);
663 map_resp->protocol = map_req->protocol;
664 map_resp->res_unuse1 = 0;
665 map_resp->int_port = map_req->int_port;
667 /* Ignore klockwork issue for below stmt */
669 rte_be_to_cpu_16(entry->data.pub_port);
670 memcpy(map_resp->ext_ip, pcp_ipv4_format, 12);
671 map_resp->ext_ip[3] = rte_bswap32(entry->data.pub_ip);
673 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
681 /* Not a PCP PEER Request(56) */
683 if ((rte_be_to_cpu_16(udp_rx->dgram_len) -
684 sizeof(struct pcp_req_hdr)) <= 55)
687 struct cgnapt_table_entry *p_entry, *s_entry;
688 struct pipeline_cgnapt_entry_key s_key;
690 struct pcp_peer_req *peer_req;
691 struct pcp_peer_resp *peer_resp;
694 (struct pcp_peer_req *)((uint8_t *) rx_pkt +
697 (struct pcp_peer_resp *)((uint8_t *) rx_pkt +
700 /* PEER Err : Creation not supporting */
701 if (pcp_req->life_time == 0) {
702 pcp_resp->life_time = 0;
703 pcp_resp->result_code = PCP_MALFORMED_REQUEST;
706 printf("PCP Failure : PEER creation not "
710 construct_pcp_resp(rx_pkt, tx_pkt, ver,
715 /* Preparing key to search the entry */
716 key.pid = rx_pkt->port;
717 /* For both IPv4 & IPv6, key is last 32 bits
720 key.ip = rte_bswap32(pcp_req->cli_ip[3]);
721 key.port = rte_bswap16(peer_req->int_port);
723 #ifdef NAT_ONLY_CONFIG_REQ
724 if (nat_only_config_flag)
728 /* PEER Err : If no requested entry is found */
729 pos = rte_hash_lookup(napt_common_table, &key);
730 if (pos == -ENOENT) {
731 pcp_resp->life_time =
732 rte_bswap32(PCP_LONG_LTIME);
733 pcp_resp->result_code = PCP_MALFORMED_REQUEST;
736 printf("PCP Failure : unable to find entry\n");
739 construct_pcp_resp(rx_pkt, tx_pkt, ver,
743 /* If requested created entry */
745 if (napt_hash_tbl_entries[pos].data.
748 napt_hash_tbl_entries[pos].
749 data.timeout = pcp_lifetime;
751 p_entry = &napt_hash_tbl_entries[pos];
753 s_key.port = napt_hash_tbl_entries[pos].
755 s_key.ip = napt_hash_tbl_entries[pos].
757 s_key.pid = napt_hash_tbl_entries[pos].
760 /* Getting ingress or second entry
764 pos = rte_hash_lookup(napt_common_table,
766 s_entry = &napt_hash_tbl_entries[pos];
768 /* Enqueue the info to restart the timer */
769 timer_thread_enqueue(&key, &s_key,
771 (struct pipeline *)p_nat);
775 if (!napt_hash_tbl_entries[pos].data.timeout)
776 pcp_resp->life_time =
777 rte_bswap32(PCP_LONG_LTIME);
778 else // if static entry
779 pcp_resp->life_time = 0xffffffff;
781 pcp_resp->result_code =
784 printf("PCP Failure : Not a PCP request "
787 construct_pcp_resp(rx_pkt, tx_pkt, ver,
794 /* Fill PCP Response */
795 rte_bswap16(pcp_req->life_time) < pcp_lifetime?
796 (pcp_resp->life_time = pcp_req->life_time):
797 (pcp_resp->life_time = rte_bswap32(pcp_lifetime));
799 pcp_resp->result_code = PCP_SUCCESS;
800 /* Fill PCP PEER Resonse */
801 memcpy(peer_resp->nonce, peer_req->nonce, 12);
802 peer_resp->protocol = peer_req->protocol;
803 peer_resp->res_unuse1 = 0;
805 peer_resp->int_port =
806 rte_be_to_cpu_16(peer_req->int_port);
807 peer_resp->ext_port =
808 rte_be_to_cpu_16(peer_req->ext_port);
809 memcpy(peer_resp->ext_ip, peer_req->ext_ip, 16);
810 memcpy(peer_resp->ext_ip, pcp_ipv4_format, 12);
811 peer_resp->ext_ip[3] =
812 rte_bswap32(p_entry->data.pub_ip);
813 peer_resp->rpeer_port =
814 rte_be_to_cpu_16(peer_req->rpeer_port);
815 peer_resp->res_unuse2 = 0x0000;
816 memcpy(peer_resp->rpeer_ip, peer_req->rpeer_ip, 16);
817 construct_pcp_resp(rx_pkt, tx_pkt, ver, p_nat->p.p);
821 printf("This never hits\n");