diff options
author | 2017-04-18 19:41:40 +0530 | |
---|---|---|
committer | 2017-04-18 02:59:07 -0700 | |
commit | 51cd08d9a3f2826088d122e2a5683315c77a2786 (patch) | |
tree | 3fac17a8f7bf362f0c77f1003615b2063d900d35 /common/VIL/l2l3_stack/lib_icmpv6.c | |
parent | 03aef84e240c5be8813634735d825420129f1460 (diff) |
common: Adding common library for sample vnf
JIRA: SAMPLEVNF-3
This patch adds common libraries required as part of the
sample vnf.
This includes the following libraries
1. ACL library
2. SIP
3. FTP
4. Connection tracker
5. L2l3 stack
- Interface Manager
- ARP & ICMPv4
- ND & ICMPv6
and other common libraries needed for ip pipeline framework
Change-Id: I117690b6b63fbcd76974cd7274518484e60980ab
Signed-off-by: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
[Push patch to gerrit]
Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'common/VIL/l2l3_stack/lib_icmpv6.c')
-rw-r--r-- | common/VIL/l2l3_stack/lib_icmpv6.c | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/common/VIL/l2l3_stack/lib_icmpv6.c b/common/VIL/l2l3_stack/lib_icmpv6.c new file mode 100644 index 00000000..44f30cbf --- /dev/null +++ b/common/VIL/l2l3_stack/lib_icmpv6.c @@ -0,0 +1,410 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// 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. +*/ +/* Santosh Sethupathi*/ + +#include "lib_icmpv6.h" + +static void print_pkt(uint8_t *rd) +{ + int i = 0, j = 0; + + printf("Packet Contents:\n"); + + for (i = 0; i < 20; i++) { + for (j = 0; j < 20; j++) + printf("%02x ", rd[(20 * i) + j]); + + printf("\n"); + } +} + +static uint16_t icmpv6_ipv6_nd_checksum(struct rte_mbuf *pkt) +{ + struct ether_hdr *eth_h; + struct ipv6_hdr *ipv6_h; + struct icmpv6_hdr *icmpv6_h; + + size_t tmplen, offset; + uint8_t *tmppacket, *tpacket; + + eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); + icmpv6_h = + (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr)); + + uint32_t payloadlen = 0x20; + payloadlen = rte_bswap32(payloadlen); + + tmplen = 40 + sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr); + tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen); + tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE); + tpacket = tmppacket; + + offset = 16; + memcpy(tpacket, &ipv6_h->src_addr[0], offset); + tpacket += offset; + memcpy(tpacket, &ipv6_h->dst_addr[0], offset); + tpacket += offset; + *tpacket = 0; + tpacket++; + *tpacket = 0; + tpacket++; + *tpacket = 0; + tpacket++; + memcpy(tpacket, &ipv6_h->proto, 1); + tpacket++; + memcpy(tpacket, &payloadlen, 4); + tpacket += 4; + memcpy(tpacket, icmpv6_h, + sizeof(struct icmpv6_hdr) + sizeof(struct icmpv6_nd_hdr)); + + if (ARPICMP_DEBUG) + print_pkt(tmppacket); + + return rte_raw_cksum(tmppacket, tmplen); +} + +static uint16_t icmpv6_ipv6_echo_checksum(struct rte_mbuf *pkt) +{ + struct ether_hdr *eth_h; + struct ipv6_hdr *ipv6_h; + struct icmpv6_hdr *icmpv6_h; + + size_t tmplen, offset; + uint8_t *tmppacket, *tpacket; + + eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); + icmpv6_h = + (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr)); + + uint32_t payloadlen = rte_bswap16(ipv6_h->payload_len); + uint32_t payloadlen_swap = rte_bswap32(payloadlen); + + if (ARPICMP_DEBUG) + printf("%s: payloadlen: %u\n", __FUNCTION__, payloadlen); + + tmplen = 40 + payloadlen; + tmplen = RTE_CACHE_LINE_ROUNDUP(tmplen); + tmppacket = rte_zmalloc(NULL, tmplen, RTE_CACHE_LINE_SIZE); + tpacket = tmppacket; + + offset = 16; + memcpy(tpacket, &ipv6_h->src_addr[0], offset); + tpacket += offset; + memcpy(tpacket, &ipv6_h->dst_addr[0], offset); + tpacket += offset; + *tpacket = 0; + tpacket++; + *tpacket = 0; + tpacket++; + *tpacket = 0; + tpacket++; + memcpy(tpacket, &ipv6_h->proto, 1); + tpacket++; + memcpy(tpacket, &payloadlen_swap, 4); + tpacket += 4; + memcpy(tpacket, icmpv6_h, payloadlen); + + if (ARPICMP_DEBUG) + print_pkt(tmppacket); + + return rte_raw_cksum(tmppacket, tmplen); +} + +void process_icmpv6_pkt(struct rte_mbuf *pkt, l2_phy_interface_t *port) +{ + + struct ether_hdr *eth_h; + struct ipv6_hdr *ipv6_h; + struct icmpv6_hdr *icmpv6_h; + struct icmpv6_nd_hdr *icmpv6_nd_h; + uint8_t ipv6_addr[16]; + uint8_t i = 0; + uint8_t req_tipv6[16]; + /* To drop the packet */ + + if (port == NULL) { + printf("port is NULL"); + return; + } else if (port->ipv6_list == NULL) { + printf("IPV6 address not configured on link\n"); + return; + } + + eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); + icmpv6_h = + (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr)); + + if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REQUEST) + && (icmpv6_h->icmpv6_code == 0)) { + for (i = 0; i < 16; i++) { + ipv6_addr[i] = ipv6_h->src_addr[i]; + } + + ether_addr_copy(ð_h->s_addr, ð_h->d_addr); + ether_addr_copy((struct ether_addr *)&port->macaddr[0], + ð_h->s_addr); + + for (i = 0; i < 16; i++) + ipv6_h->src_addr[i] = ipv6_h->dst_addr[i]; + for (i = 0; i < 16; i++) + ipv6_h->dst_addr[i] = ipv6_addr[i]; + + icmpv6_h->icmpv6_type = ICMPV6_ECHO_REPLY; + icmpv6_h->icmpv6_cksum = 0; + icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(pkt); + port->transmit_bulk_pkts(port, &pkt, 1); + + return; + } else if ((icmpv6_h->icmpv6_type == ICMPV6_ECHO_REPLY) + && (icmpv6_h->icmpv6_code == 0)) { + struct nd_key_ipv6 nd_key; + nd_key.port_id = port->pmdid; + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) { + nd_key.ipv6[i] = ipv6_h->src_addr[i]; + + } + nd_key.filler1 = 0; + nd_key.filler2 = 0; + nd_key.filler3 = 0; + + /*Validate if key-value pair already exists in the hash table for ND IPv6 */ + struct nd_entry_data *new_nd_data = retrieve_nd_entry(nd_key); + if (new_nd_data == NULL) { + printf + ("Received unsolicited ICMPv6 echo reply on port %d\n", + nd_key.port_id); + for (i = 0; i < ND_IPV6_ADDR_SIZE; i += 2) { + printf("%02X%02X ", nd_key.ipv6[i], + nd_key.ipv6[i + 1]); + } + return; + } + + new_nd_data->status = COMPLETE; + } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_SOLICITATION) + && (icmpv6_h->icmpv6_code == 0)) { + + icmpv6_nd_h = + (struct icmpv6_nd_hdr *)((char *)icmpv6_h + + sizeof(struct icmpv6_hdr)); + struct ether_addr *src_hw_addr = ð_h->s_addr; + uint8_t src_ipv6[16], dst_ipv6[16]; + uint16_t multi_addr; + + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + src_ipv6[i] = ipv6_h->src_addr[i]; + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + dst_ipv6[i] = ipv6_h->dst_addr[i]; + + multi_addr = dst_ipv6[0]; + + /* Check for Multicast Address */ + if ((IPV6_MULTICAST & ((multi_addr << 8) | dst_ipv6[1])) + || !memcmp(&port->macaddr[0], ð_h->d_addr, 6)) { + populate_nd_entry(src_hw_addr, src_ipv6, port->pmdid, + DYNAMIC_ND); + + /* build a Neighbor Advertisement message */ + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + req_tipv6[i] = icmpv6_nd_h->target_ipv6[i]; + + if (!memcmp + (&req_tipv6[0], + &((ipv6list_t *) port->ipv6_list)->ipaddr[0], + 16)) { + + ether_addr_copy(ð_h->s_addr, ð_h->d_addr); + ether_addr_copy((struct ether_addr *)&port-> + macaddr[0], ð_h->s_addr); + + /* set sender mac address */ + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + ipv6_h->dst_addr[i] = + ipv6_h->src_addr[i]; + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + ipv6_h->src_addr[i] = req_tipv6[i]; + icmpv6_h->icmpv6_type = + ICMPV6_NEIGHBOR_ADVERTISEMENT; + icmpv6_nd_h->type = e_Target_Link_Layer_Address; + icmpv6_nd_h->length = 1; + memcpy(&icmpv6_nd_h->link_layer_addr[0], + &port->macaddr[0], 6); + icmpv6_nd_h->icmpv6_reserved = 0; + icmpv6_nd_h->icmpv6_reserved |= + rte_cpu_to_be_32 + (NEIGHBOR_ROUTER_OVERRIDE_SET); + + icmpv6_h->icmpv6_cksum = 0; + icmpv6_h->icmpv6_cksum = + ~icmpv6_ipv6_nd_checksum(pkt); + + port->transmit_bulk_pkts(port, &pkt, 1); + + } else if (ARPICMP_DEBUG) { + printf + ("............Some one else is the target host here !!!\n"); + } + + return; + } else { + if (ARPICMP_DEBUG) { + printf + ("...............Malformed ND Solicitation message!!!\n"); + } + } + + } else if ((icmpv6_h->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT) + && (icmpv6_h->icmpv6_code == 0)) { + struct ether_addr *src_hw_addr = ð_h->s_addr; + uint8_t ipv6[16]; + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) { + ipv6[i] = ipv6_h->src_addr[i]; + + } + populate_nd_entry(src_hw_addr, ipv6, port->pmdid, DYNAMIC_ND); + } else { + if (ARPICMP_DEBUG) { + printf("ICMPv6 Type %d Not Supported yet !!!\n", + icmpv6_h->icmpv6_type); + } + } + + rte_pktmbuf_free(pkt); +} + +struct rte_mbuf *request_icmpv6_echo(uint8_t ipv6[], l2_phy_interface_t *port) +{ + struct ether_hdr *eth_h; + struct ipv6_hdr *ipv6_h; + struct icmpv6_hdr *icmpv6_h; + struct icmpv6_info_hdr *icmpv6_info_h; + int i; + uint8_t *icmp_data; + + struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt; + if (icmpv6_pkt == NULL) { + if (ARPICMP_DEBUG) + printf("Error allocating icmpv6_pkt rte_mbuf\n"); + return NULL; + } + + eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *); + + ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); + icmpv6_h = + (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr)); + icmpv6_info_h = + (struct icmpv6_info_hdr *)((char *)icmpv6_h + + sizeof(struct icmpv6_hdr)); + + ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr); + eth_h->ether_type = rte_bswap16(0x86dd); + for (i = 0; i < 6; i++) { + eth_h->d_addr.addr_bytes[i] = 0; + } + + ipv6_h->vtc_flow = rte_bswap32(0x60000000); + ipv6_h->payload_len = rte_bswap16(64); + ipv6_h->proto = 58; + ipv6_h->hop_limits = 64; + + for (i = 0; i < 16; i++) { + ipv6_h->src_addr[i] = 0x0; + ipv6_h->dst_addr[i] = ipv6[i]; + } + + icmpv6_h->icmpv6_type = ICMPV6_ECHO_REQUEST; + icmpv6_h->icmpv6_code = 0; + icmpv6_info_h->icmpv6_ident = rte_bswap16(0x5151); + icmpv6_info_h->icmpv6_seq_nb = rte_bswap16(0x1); + + icmp_data = (uint8_t *) icmpv6_h + 8; + for (i = 0; i < 56; i++) { + *icmp_data = i + 1; + icmp_data++; + } + icmpv6_h->icmpv6_cksum = 0; + icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_echo_checksum(icmpv6_pkt); + + icmpv6_pkt->pkt_len = + sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 64; + icmpv6_pkt->data_len = icmpv6_pkt->pkt_len; + + return icmpv6_pkt; +} + +struct rte_mbuf *request_nd(uint8_t ipv6[], l2_phy_interface_t *port) +{ + struct ether_hdr *eth_h; + struct ipv6_hdr *ipv6_h; + struct icmpv6_hdr *icmpv6_h; + struct icmpv6_nd_hdr *icmpv6_nd_h; + int i; + + struct rte_mbuf *icmpv6_pkt = lib_icmpv6_pkt; + if (icmpv6_pkt == NULL) { + if (ARPICMP_DEBUG) + printf("Error allocating icmpv6_pkt rte_mbuf\n"); + return NULL; + } + + eth_h = rte_pktmbuf_mtod(icmpv6_pkt, struct ether_hdr *); + + ipv6_h = (struct ipv6_hdr *)((char *)eth_h + sizeof(struct ether_hdr)); + icmpv6_h = + (struct icmpv6_hdr *)((char *)ipv6_h + sizeof(struct ipv6_hdr)); + icmpv6_nd_h = + (struct icmpv6_nd_hdr *)((char *)icmpv6_h + + sizeof(struct icmpv6_hdr)); + + ether_addr_copy((struct ether_addr *)&port->macaddr[0], ð_h->s_addr); + eth_h->ether_type = rte_bswap16(0x86dd); + for (i = 0; i < 6; i++) { + eth_h->d_addr.addr_bytes[i] = 0; + } + + ipv6_h->vtc_flow = 0x60000000; + ipv6_h->payload_len = rte_bswap16(32); + ipv6_h->proto = 58; + ipv6_h->hop_limits = 64; + + for (i = 0; i < 16; i++) { + ipv6_h->src_addr[i] = 0x0; + ipv6_h->dst_addr[i] = ipv6[i]; + } + + icmpv6_h->icmpv6_type = ICMPV6_NEIGHBOR_SOLICITATION; + icmpv6_h->icmpv6_code = 0; + + icmpv6_nd_h->icmpv6_reserved = 0x0; + for (i = 0; i < ND_IPV6_ADDR_SIZE; i++) + icmpv6_nd_h->target_ipv6[i] = ipv6[i]; + icmpv6_nd_h->type = e_Source_Link_Layer_Address; + icmpv6_nd_h->length = 1; + memcpy(&icmpv6_nd_h->link_layer_addr[0], &port->macaddr[0], 6); + + icmpv6_h->icmpv6_cksum = 0; + icmpv6_h->icmpv6_cksum = ~icmpv6_ipv6_nd_checksum(icmpv6_pkt); + + icmpv6_pkt->pkt_len = + sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr) + 32; + icmpv6_pkt->data_len = icmpv6_pkt->pkt_len; + + return icmpv6_pkt; +} |