diff options
Diffstat (limited to 'stacks/lwip_stack/lwip_src/core/spl_pbuf.c')
-rw-r--r-- | stacks/lwip_stack/lwip_src/core/spl_pbuf.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/stacks/lwip_stack/lwip_src/core/spl_pbuf.c b/stacks/lwip_stack/lwip_src/core/spl_pbuf.c new file mode 100644 index 0000000..dea577f --- /dev/null +++ b/stacks/lwip_stack/lwip_src/core/spl_pbuf.c @@ -0,0 +1,605 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "spl_opt.h" + +#include "spl_def.h" +#include "spl_pbuf.h" +#include "stackx_pbuf.h" + +#include "stackx_spl_share.h" +#include "spl_api.h" + +#include "nsfw_maintain_api.h" +#include "netif/sc_dpdk.h" +#include <common_mem_mbuf.h> + +#include <string.h> +#include "nstack_log.h" +#include "nstack_securec.h" +#include "spl_instance.h" + +#include "sys.h" +#include "mem.h" +#include "memp.h" +//#include "sockets.h" +//#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAL_LIB +#else +#include "rte_memcpy.h" +#endif +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct spl_pbuf)) +u16_t g_offSetArry[SPL_PBUF_MAX_LAYER]; + +u16_t g_offSetArry[SPL_PBUF_MAX_LAYER] = + { PBUF_TRANSPORT_HLEN + PBUF_IP_HLEN + SPL_PBUF_LINK_HLEN, + SPL_PBUF_UDP_HLEN + PBUF_IP_HLEN + SPL_PBUF_LINK_HLEN, + PBUF_IP_HLEN + SPL_PBUF_LINK_HLEN, + SPL_PBUF_LINK_HLEN, + 0 +}; + +inline struct spl_pbuf *spl_pbuf_alloc_hugepage(spl_pbuf_layer layer, + u16_t length, + spl_pbuf_type Type, + u16_t proc_id, void *net_conn) +{ + struct spl_pbuf *p; + u16_t offset; + u16_t count = 0; + spl_netconn_t *conn = (spl_netconn_t *) net_conn; + + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, + "spl_pbuf_alloc_hugepage]length=%" U16_F, length); + + /* determine header offset */ + if (likely(layer < SPL_PBUF_MAX_LAYER)) + { + offset = g_offSetArry[layer]; + } + else + { + NSPOL_LOGERR("spl_pbuf_alloc_hugepage: bad pbuf layer"); + return NULL; + } + + if (unlikely(length < offset || Type != SPL_PBUF_HUGE)) + { + NSPOL_LOGERR("input is invalid!]length=%u, Type = %d", length, Type); + return NULL; + } + + p = spl_mbuf_malloc(length, SPL_PBUF_HUGE, &count); + + if (p == NULL) + { + /* last_log_prt_time and unprint_log_count indeed have multi-thread issue, + * but their values don't have precision requirement. No risk. */ + NS_LOG_CTRL(LOG_CTRL_HUGEPAGE_ALLOC_FAIL, STACKPOOL, "NSLWIP", + NSLOG_ERR, + "pbuf_alloc_huge: Could not allocate PBUF for SPL_PBUF_HUGE"); + + return NULL; + } + + if (conn) + { + p->conn_a = ADDR_LTOSH(conn); + } + else + { + p->conn_a = 0; + } + + p->tot_len -= offset; + p->len -= offset; + p->next_a = 0; + + p->payload_a = p->payload_a + offset; + + p->proto_type = SPL_PBUF_PROTO_NONE; + + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, + "pbuf_alloc]length=%" U16_F ",p=%p", length, (void *) p); + return p; +} + +inline int spl_pbuf_internal_copy(struct spl_pbuf *dst, struct spl_pbuf *src) +{ + u32_t dst_len = dst->len; + u32_t src_len = src->len; + u32_t dst_pos = 0; + u32_t src_pos = 0; + while (dst != NULL && src != NULL) + { + if (dst_len > src_len) + { + if (NULL == + common_memcpy(PTR_SHTOL(char *, dst->payload_a) + dst_pos, + PTR_SHTOL(char *, src->payload_a) + src_pos, + src_len)) + { + NSPOL_LOGERR("rte_memcpy error"); + return -1; + } + + dst_len -= src_len; + dst_pos += src_len; + src = ADDR_SHTOL(src->next_a); + src_len = src != NULL ? src->len : 0; + src_pos = 0; + } + else if (dst_len < src_len) + { + if (NULL == + common_memcpy(PTR_SHTOL(char *, dst->payload_a) + dst_pos, + PTR_SHTOL(char *, src->payload_a) + src_pos, + dst_len)) + { + NSPOL_LOGERR("rte_memcpy error"); + return -1; + } + + src_len -= dst_len; + src_pos += dst_len; + dst = ADDR_SHTOL(dst->next_a); + dst_len = dst != NULL ? dst->len : 0; + dst_pos = 0; + } + else + { + if (NULL == + common_memcpy(PTR_SHTOL(char *, dst->payload_a) + dst_pos, + PTR_SHTOL(char *, src->payload_a) + src_pos, + dst_len)) + { + NSPOL_LOGERR("rte_memcpy error"); + return -1; + } + + src = ADDR_SHTOL(src->next_a); + src_len = src != NULL ? src->len : 0; + src_pos = 0; + dst = ADDR_SHTOL(dst->next_a); + dst_len = dst != NULL ? dst->len : 0; + dst_pos = 0; + } + } + return 0; +} + +void spl_pbuf_realloc(struct spl_pbuf *p, u32_t new_len) +{ + if (NULL != p && p->type == SPL_PBUF_HUGE) + { + p->tot_len = new_len; + p->len = new_len; + return; + } +} + +void spl_pbuf_free(struct spl_pbuf *p) +{ + struct spl_pbuf *q; + u8_t count = 0; + + NSPOL_LOGINF(PBUF_DEBUG, "Freeing PBF %p", p); + + if (unlikely(p == NULL || p->type != SPL_PBUF_HUGE)) + { + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_LEVEL_SERIOUS, + "input param illegal]p=%p, type=%d", p, + p ? p->type : -1); + return; + } + + (void) count; + + /* de-allocate all consecutive pbufs from the head of the chain that + * obtain a zero reference count after decrementing*/ + do + { + /* remember next pbuf in chain for next iteration */ + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, + "spl_pbuf_free: deallocating]buf=%p", (void *) p); + q = (struct spl_pbuf *) ADDR_SHTOL(p->next_a); + if (res_free(&p->res_chk)) + { + //NSPOL_LOGERR("res_free failed]p=%p", p); + } + + count++; + { + pbuf_set_recycle_flg(p, MBUF_UNUSED); /* release buf hold by app on abnormal exit */ + spl_mbuf_free((char *) p - sizeof(struct common_mem_mbuf)); + p->res_chk.u8Reserve |= PBUF_FREE_FLAG; + } + + /* proceed to next pbuf */ + p = q; + } + while (p != NULL); + + /* return number of de-allocated pbufs */ + return; +} + +void spl_pbuf_cat(struct spl_pbuf *h, struct spl_pbuf *t) +{ + struct spl_pbuf *p; + + if (h == NULL || t == NULL) + { + NSPOL_LOGERR("pbuf_cat: h=NULL||t=NULL!!"); + return; + } + + for (p = h; p->next_a != 0; p = PTR_SHTOL(struct spl_pbuf *, p->next_a)) + { + /* add total length of second chain to all totals of first chain */ + p->tot_len += t->tot_len; + } + + if (0 != p->next_a) + { + NSPOL_LOGERR + ("pbuf_cat: p is not the last pbuf of the first chain, p->next_a != 0"); + return; + } + + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len += t->tot_len; + + /* chain last pbuf of head (p) with first of tail (t) */ + p->next_a = (uint64_t) ADDR_LTOSH_EXT(t); + + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. + */ +} + +err_t spl_pbuf_copy(struct spl_pbuf * p_to, struct spl_pbuf * p_from) +{ + u32_t offset_to = 0; + u32_t offset_from = 0; + u32_t len = 0; + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, "pbuf_copy]p_to=%p,p_from=%p", + (void *) p_to, (void *) p_from); + + if (! + ((p_to != NULL) && (p_from != NULL) + && (p_to->tot_len >= p_from->tot_len))) + { + NSPOL_LOGERR("pbuf_copy: target not big enough to hold source"); + return ERR_ARG; + } + + do + { + if (p_to == NULL) + { + NSPOL_LOGERR("pbuf_copy: target pbuf not exist: p_to == NULL!!"); + return ERR_ARG; + } + + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) + { + + len = p_from->len - offset_from; + } + else + { + + len = p_to->len - offset_to; + } + + if (EOK != + memmove_s((u8_t *) ADDR_SHTOL(p_to->payload_a) + offset_to, len, + (u8_t *) ADDR_SHTOL(p_from->payload_a) + offset_from, + len)) + { + NSPOL_LOGERR("MEMMOVE_S failed"); + return ERR_MEM; + } + + offset_to += len; + offset_from += len; + if (offset_to > p_to->len) + { + NSPOL_LOGERR + ("pbuf_copy: target offset not match: offset_to > p_to->len."); + return ERR_VAL; + } + if (offset_to == p_to->len) + { + offset_to = 0; + p_to = (struct spl_pbuf *) ADDR_SHTOL(p_to->next_a); + } + + if (offset_from >= p_from->len) + { + /* on to next p_from (if any) */ + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, + "pbuf_copy: source offset not match: offset_from >= p_from->len"); + offset_from = 0; + p_from = (struct spl_pbuf *) ADDR_SHTOL(p_from->next_a); + } + + if ((p_from != NULL) && (p_from->len == p_from->tot_len)) + { + if ((p_from->next_a != 0)) + { + NSPOL_LOGERR("pbuf_copy() does not allow packet queues!"); + return ERR_VAL; + } + } + + if ((p_to != NULL) && (p_to->len == p_to->tot_len)) + { + /* don't copy more than one packet! */ + if ((p_to->next_a != 0)) + { + NSPOL_LOGERR("pbuf_copy() does not allow packet queues!"); + return ERR_VAL; + } + } + } + while (p_from); + + NSPOL_LOGDBG(PBUF_DEBUG | STACKX_DBG_TRACE, + "pbuf_copy: end of chain reached."); + return ERR_OK; +} + +err_t +splpbuf_to_pbuf_transport_copy(struct pbuf * p_to, struct spl_pbuf * p_from) +{ + if (EOK != memmove_s((u8_t *) p_to->payload, + p_to->len, (u8_t *) ADDR_SHTOL(p_from->payload_a), + p_from->len)) + { + NSPOL_LOGERR("MEMMOVE_S failed"); + return ERR_MEM; + } + + return ERR_OK; +} + +err_t splpbuf_to_pbuf_copy(struct pbuf * p_to, struct spl_pbuf * p_from) +{ + u32_t offset_to = 0; + u32_t offset_from = 0; + u32_t len = 0; + + NSPOL_LOGINF(NETIF_DEBUG, "splpbuf_to_pbuf_copy"); + + if (! + ((p_to != NULL) && (p_from != NULL) + && (p_to->tot_len >= p_from->tot_len))) + { + NSPOL_LOGERR + ("splpbuf_to_pbuf_copy: target not big enough to hold source"); + return ERR_ARG; + } + NSPOL_LOGINF(PBUF_DEBUG, + "splpbuf_to_pbuf_copy]p_to=%p [type %d tot_len %d], p_from=%p [type %d tot_len %d]", + (void *) p_to, p_to->type, p_to->tot_len, (void *) p_from, + p_from->type, p_from->tot_len); + do + { + NSPOL_LOGINF(NETIF_DEBUG, "copying...."); + if (p_to == NULL) + { + NSPOL_LOGERR + ("splpbuf_to_pbuf_copy: target not big enough to hold source p_to len [%d] p_from len [%d]", + p_to->tot_len, p_from->tot_len); + return ERR_ARG; + } + + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) + { + + len = p_from->len - offset_from; + } + else + { + + len = p_to->len - offset_to; + } + + if (EOK != memmove_s((u8_t *) p_to->payload + offset_to, + len, + (u8_t *) ADDR_SHTOL(p_from->payload_a) + + offset_from, len)) + { + NSPOL_LOGERR("MEMMOVE_S failed"); + return ERR_MEM; + } + + offset_to += len; + offset_from += len; + if (offset_to > p_to->len) + { + NSPOL_LOGERR + ("splpbuf_to_pbuf_copy: target offset not match: offset_to > p_to->len."); + return ERR_VAL; + } + if (offset_to == p_to->len) + { + offset_to = 0; + p_to = p_to->next; + + NSPOL_LOGINF(NETIF_DEBUG, + "splpbuf_to_pbuf_copy: p_to next %p", p_to); + } + + if (offset_from >= p_from->len) + { + /* on to next p_from (if any) */ + NSPOL_LOGINF(NETIF_DEBUG, + "splpbuf_to_pbuf_copy: source offset not match: offset_from >= p_from->len"); + offset_from = 0; + p_from = (struct spl_pbuf *) ADDR_SHTOL(p_from->next_a); + NSPOL_LOGINF(NETIF_DEBUG, + "splpbuf_to_pbuf_copy: pfrom next %p", p_from); + } + + if ((p_from != NULL) && (p_from->len == p_from->tot_len)) + { + if ((p_from->next_a != 0)) + { + NSPOL_LOGERR + ("splpbuf_to_pbuf_copy() does not allow packet queues!"); + return ERR_VAL; + } + } + + if ((p_to != NULL) && (p_to->len == p_to->tot_len)) + { + /* don't copy more than one packet! */ + if ((p_to->next != NULL)) + { + NSPOL_LOGERR + ("splpbuf_to_pbuf_copy() does not allow packet queues!"); + return ERR_VAL; + } + } + } + while (p_from); + + NSPOL_LOGDBG(NETIF_DEBUG, "splpbuf_to_pbuf_copy: end of chain reached."); + return ERR_OK; +} + +err_t pbuf_to_splpbuf_copy(struct spl_pbuf * p_to, struct pbuf * p_from) +{ + int offset = 0; + void *data = NULL; + + do + { + data = (u8_t *) (p_to->payload_a) + offset; + memcpy(data, (u8_t *) p_from->payload, p_from->len); + offset = offset + p_from->len; + if (offset >= 2048) + { + NSPOL_LOGERR("More thank 2K size"); + return ERR_MEM; + } + p_from = p_from->next; + } + while (p_from != NULL); + + return ERR_OK; +} + +struct pbuf *spl_convert_spl_pbuf_to_pbuf(struct spl_pbuf *p_from) +{ + struct pbuf *p_to = NULL; + + p_to = pbuf_alloc(PBUF_RAW, p_from->tot_len, PBUF_POOL); + if (p_to) + { + splpbuf_to_pbuf_copy(p_to, p_from); + } + return p_to; +} + +spl_pbuf_layer get_pbuf_layer_from_pbuf_payload(struct pbuf * buf) +{ + + struct eth_hdr *ethhdr; + spl_pbuf_layer layer = SPL_PBUF_TRANSPORT; + u16_t type; + + if (buf->len <= SIZEOF_ETH_HDR) + { + NSPOL_LOGINF(PBUF_DEBUG, + "get_pbuf_layer_from_payload failed. length is wrong"); + return layer; + } + ethhdr = (struct eth_hdr *) buf->payload; + type = spl_htons(ethhdr->type); + + NSPOL_LOGINF(PBUF_DEBUG, "packet type %x", type); + + switch (type) + { + case ETHTYPE_IP: + layer = SPL_PBUF_IP; + break; + case ETHTYPE_ARP: + layer = SPL_PBUF_LINK; + break; + default: + layer = SPL_PBUF_TRANSPORT; + break; + } + + return layer; +} + +void print_pbuf_payload_info(struct pbuf *buf, bool send) +{ + + struct eth_hdr *ethhdr; + u16_t type; + + if (buf->len <= SIZEOF_ETH_HDR) + { + NSPOL_LOGINF(PBUF_DEBUG, + "get_pbuf_layer_from_payload failed. length is wrong"); + return; + } + ethhdr = (struct eth_hdr *) buf->payload; + type = spl_htons(ethhdr->type); + + if (send) + { + NSPOL_LOGINF(PBUF_DEBUG, "send packet start type %x len %d *****", + type, buf->len); + } + else + { + NSPOL_LOGINF(PBUF_DEBUG, + "receive packet start type %x len %d ########", type, + buf->len); + } + + switch (type) + { + case ETHTYPE_IP: + NSPOL_LOGINF(TCPIP_DEBUG, "ip packet len %d tot len %d type %x", + buf->len, buf->tot_len, type); + struct ip_hdr *ip = + (struct ip_hdr *) ((char *) buf->payload + SIZEOF_ETH_HDR); + NSPOL_LOGINF(PBUF_DEBUG, "ip packet src %x dest %x proto %d", + ip->src, ip->dest, ip->_proto); + break; + case ETHTYPE_ARP: + NSPOL_LOGINF(TCPIP_DEBUG, "arp packet len %d tot len %d type %x", + buf->len, buf->tot_len, type); + break; + default: + NSPOL_LOGINF(TCPIP_DEBUG, + "other packet len %d tot len %d type %x", buf->len, + buf->tot_len, type); + break; + } + return; +} |