diff options
Diffstat (limited to 'extras/libmemif/examples/common')
-rw-r--r-- | extras/libmemif/examples/common/common.c | 192 | ||||
-rw-r--r-- | extras/libmemif/examples/common/common.h | 116 | ||||
-rw-r--r-- | extras/libmemif/examples/common/icmp_proto.c | 520 | ||||
-rw-r--r-- | extras/libmemif/examples/common/icmp_proto.h | 48 | ||||
-rw-r--r-- | extras/libmemif/examples/common/packet_handler.c | 65 | ||||
-rw-r--r-- | extras/libmemif/examples/common/responder.c | 172 | ||||
-rw-r--r-- | extras/libmemif/examples/common/sender.c | 55 |
7 files changed, 1168 insertions, 0 deletions
diff --git a/extras/libmemif/examples/common/common.c b/extras/libmemif/examples/common/common.c new file mode 100644 index 00000000000..5af42eaf63b --- /dev/null +++ b/extras/libmemif/examples/common/common.c @@ -0,0 +1,192 @@ +#include <common.h> + +void +print_memif_ring_details (memif_connection_t *c, uint16_t qid, uint8_t is_rx) +{ + /* TODO: print memif shared memory details */ +} + +void +print_memif_rx_ring_details (memif_connection_t *c, uint16_t qid) +{ + print_memif_ring_details (c, qid, /* RX */ 1); +} + +void +print_memif_tx_ring_details (memif_connection_t *c, uint16_t qid) +{ + print_memif_ring_details (c, qid, /* TX */ 0); +} + +void +print_version () +{ + printf ("libmemif version: %s, memif version: %s\n", LIBMEMIF_VERSION, + memif_get_version_str ()); +} + +int +parse_ip4 (const char *input, uint8_t out[4]) +{ + char *ui, *end; + char *tmp = strdup (input); + + ui = strtok (tmp, "."); + if (ui == NULL) + return -1; + out[0] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + return -1; + out[1] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + return -1; + out[2] = strtol (ui, &end, 10); + + ui = strtok (NULL, "."); + if (ui == NULL) + return -1; + out[3] = strtol (ui, &end, 10); + + free (tmp); + + return 0; +} + +int +parse_mac (const char *input, uint8_t out[6]) +{ + char *ui, *end; + char *tmp = strdup (input); + + ui = strtok (tmp, ":"); + if (ui == NULL) + return -1; + out[0] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + return -1; + out[1] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + return -1; + out[2] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + return -1; + out[3] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + return -1; + out[4] = strtol (ui, &end, 16); + ui = strtok (NULL, ":"); + if (ui == NULL) + return -1; + out[5] = strtol (ui, &end, 16); + + free (tmp); + + return 0; +} + +void +alloc_memif_buffers (memif_connection_t *c) +{ + c->rx_bufs = + (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS); + c->rx_buf_num = 0; + c->tx_bufs = + (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS); + c->tx_buf_num = 0; +} + +void +free_memif_buffers (memif_connection_t *c) +{ + if (c->rx_bufs != NULL) + free (c->rx_bufs); + c->rx_bufs = NULL; + c->rx_buf_num = 0; + if (c->tx_bufs != NULL) + free (c->tx_bufs); + c->tx_bufs = NULL; + c->tx_buf_num = 0; +} + +void +print_memif_details (memif_connection_t *c) +{ + printf ("MEMIF DETAILS\n"); + printf ("==============================\n"); + + memif_details_t md; + memset (&md, 0, sizeof (md)); + ssize_t buflen = 2048; + char *buf = (char *) malloc (buflen); + memset (buf, 0, buflen); + int err, e; + + err = memif_get_details (c->conn, &md, buf, buflen); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("%s", memif_strerror (err)); + if (err == MEMIF_ERR_NOCONN) + { + free (buf); + return; + } + } + + printf ("\tinterface name: %s\n", (char *) md.if_name); + printf ("\tapp name: %s\n", (char *) md.inst_name); + printf ("\tremote interface name: %s\n", (char *) md.remote_if_name); + printf ("\tremote app name: %s\n", (char *) md.remote_inst_name); + printf ("\tid: %u\n", md.id); + printf ("\tsecret: %s\n", (char *) md.secret); + printf ("\trole: "); + if (md.role) + printf ("slave\n"); + else + printf ("master\n"); + printf ("\tmode: "); + switch (md.mode) + { + case 0: + printf ("ethernet\n"); + break; + case 1: + printf ("ip\n"); + break; + case 2: + printf ("punt/inject\n"); + break; + default: + printf ("unknown\n"); + break; + } + printf ("\tsocket path: %s\n", (char *) md.socket_path); + printf ("\trx queues:\n"); + for (e = 0; e < md.rx_queues_num; e++) + { + printf ("\t\tqueue id: %u\n", md.rx_queues[e].qid); + printf ("\t\tring size: %u\n", md.rx_queues[e].ring_size); + printf ("\t\tbuffer size: %u\n", md.rx_queues[e].buffer_size); + } + printf ("\ttx queues:\n"); + for (e = 0; e < md.tx_queues_num; e++) + { + printf ("\t\tqueue id: %u\n", md.tx_queues[e].qid); + printf ("\t\tring size: %u\n", md.tx_queues[e].ring_size); + printf ("\t\tbuffer size: %u\n", md.tx_queues[e].buffer_size); + } + printf ("\tlink: "); + if (md.link_up_down) + printf ("up\n"); + else + printf ("down\n"); + + free (buf); +} diff --git a/extras/libmemif/examples/common/common.h b/extras/libmemif/examples/common/common.h new file mode 100644 index 00000000000..ce4ead2d253 --- /dev/null +++ b/extras/libmemif/examples/common/common.h @@ -0,0 +1,116 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2020 Cisco and/or its affiliates. + * 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. + *------------------------------------------------------------------ + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include <libmemif.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> + +#ifdef ICMP_DBG +#define DBG(...) \ + do \ + { \ + printf (APP_NAME ":%s:%d: ", __func__, __LINE__); \ + printf (__VA_ARGS__); \ + printf ("\n"); \ + } \ + while (0) +#else +#define DBG(...) +#endif + +#define INFO(...) \ + do \ + { \ + printf ("INFO: " __VA_ARGS__); \ + printf ("\n"); \ + } \ + while (0) + +/* maximum tx/rx memif buffers */ +#define MAX_MEMIF_BUFS 256 + +struct memif_connection; + +typedef int (memif_packet_handler_t) (struct memif_connection *conn); + +typedef int (packet_generator_t) (struct memif_connection *c, + uint16_t num_pkts); + +typedef struct memif_connection +{ + uint16_t index; + /* memif conenction handle */ + memif_conn_handle_t conn; + uint8_t is_connected; + /* transmit queue id */ + uint16_t tx_qid; + /* tx buffers */ + memif_buffer_t *tx_bufs; + /* allocated tx buffers counter */ + /* number of tx buffers pointing to shared memory */ + uint16_t tx_buf_num; + /* rx buffers */ + memif_buffer_t *rx_bufs; + /* allcoated rx buffers counter */ + /* number of rx buffers pointing to shared memory */ + uint16_t rx_buf_num; + memif_packet_handler_t *packet_handler; + /* interface ip address */ + uint8_t ip_addr[4]; + /* interface hw address */ + uint8_t hw_addr[6]; +} memif_connection_t; + +void print_version (); + +int parse_ip4 (const char *input, uint8_t out[4]); + +int parse_mac (const char *input, uint8_t out[6]); + +void alloc_memif_buffers (memif_connection_t *c); + +void free_memif_buffers (memif_connection_t *c); + +void print_memif_details (memif_connection_t *c); + +void print_memif_rx_ring_details (memif_connection_t *c, uint16_t qid); + +void print_memif_tx_ring_details (memif_connection_t *c, uint16_t qid); + +int send_packets (memif_connection_t *conn, uint16_t qid, + packet_generator_t *gen, uint32_t num_pkts, + uint16_t max_pkt_size); + +/* Expect packets smaller than 2048b */ +int responder (memif_conn_handle_t conn, void *private_ctx, uint16_t qid); + +/* Expect packets smaller than 2048b */ +int responder_zero_copy (memif_conn_handle_t conn, void *private_ctx, + uint16_t qid); + +/* reply with the same data */ +int basic_packet_handler (memif_connection_t *conn); + +/* ICMPv4 and ARP handler */ +int icmp_packet_handler (memif_connection_t *conn); + +#endif /* COMMON_H */
\ No newline at end of file diff --git a/extras/libmemif/examples/common/icmp_proto.c b/extras/libmemif/examples/common/icmp_proto.c new file mode 100644 index 00000000000..fafc8e425b9 --- /dev/null +++ b/extras/libmemif/examples/common/icmp_proto.c @@ -0,0 +1,520 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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 <stdint.h> +#include <net/if.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> +#include <sys/mman.h> +#include <sys/prctl.h> +#include <inttypes.h> +#include <string.h> +#include <stdio.h> +#include <netdb.h> +#include <linux/ip.h> +#include <linux/icmp.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <netinet/if_ether.h> +#include <net/if_arp.h> +#include <asm/byteorder.h> +#include <byteswap.h> +#include <assert.h> + +#include <icmp_proto.h> + +static uint16_t +cksum (void *addr, ssize_t len) +{ + char *data = (char *) addr; + + uint32_t acc = 0xffff; + + ssize_t i; + for (i = 0; (i + 1) < len; i += 2) + { + uint16_t word; + memcpy (&word, data + i, 2); + acc += ntohs (word); + if (acc > 0xffff) + acc -= 0xffff; + } + + if (len & 1) + { + uint16_t word = 0; + memcpy (&word, data + len - 1, 1); + acc += ntohs (word); + if (acc > 0xffff) + acc -= 0xffff; + } + return htons (~acc); +} + +int +print_packet (void *pck) +{ + if (pck == NULL) + { + printf ("ICMP_PROTO: no data\n"); + return -1; + } + struct iphdr *ip; + struct icmphdr *icmp; + ip = (struct iphdr *) pck; + icmp = (struct icmphdr *) (pck + sizeof (struct iphdr)); + printf ("received packet:\n"); + printf ("\tiphdr:\n"); + printf ("\t\tihl: %u\n\t\tversion: %u\n\t\tlen: %u\n\t\tid: %u\n", ip->ihl, + ip->version, __bswap_16 (ip->tot_len), ip->id); + printf ("\t\tprotocol: %u\n", ip->protocol); + + printf ("\t\tsaddr: "); + int i; + for (i = 0; i < 4; i++) + { + printf ("%u.", ((uint8_t *) &ip->saddr)[i]); + } + printf ("\n"); + + printf ("\t\tdaddr: "); + for (i = 0; i < 4; i++) + { + printf ("%u.", ((uint8_t *) &ip->daddr)[i]); + } + printf ("\n"); + printf ("\ticmphdr:\n"); + printf ("\t\ttype: %s\n", + (icmp->type == ICMP_ECHO) ? "ICMP_ECHO" : "ICMP_ECHOREPLY"); + + return 0; +} + +static ssize_t +resolve_arp (void *arp) +{ + struct arphdr *resp = (struct arphdr *) arp; + + resp->ar_hrd = __bswap_16 (ARPHRD_ETHER); + + resp->ar_pro = __bswap_16 (0x0800); + + resp->ar_hln = 6; + resp->ar_pln = 4; + + resp->ar_op = __bswap_16 (ARPOP_REPLY); + + return sizeof (struct arphdr); +} + +static ssize_t +resolve_eth_arp (struct ether_arp *eth_arp, void *eth_arp_resp, + uint8_t ip_addr[4]) +{ + struct ether_arp *resp = (struct ether_arp *) eth_arp_resp; + + resolve_arp (&resp->ea_hdr); + + memcpy (resp->arp_tha, eth_arp->arp_sha, 6); + memcpy (resp->arp_tpa, eth_arp->arp_spa, 4); + + memcpy ( + resp->arp_sha, + (((struct ether_header *) (eth_arp_resp - sizeof (struct ether_header))) + ->ether_shost), + 6); + + memcpy (resp->arp_spa, ip_addr, 4); + + return sizeof (struct ether_arp); +} + +static ssize_t +resolve_eth (struct ether_header *eth, void *eth_resp, uint8_t hw_addr[6]) +{ + struct ether_header *resp = (struct ether_header *) eth_resp; + memcpy (resp->ether_dhost, eth->ether_shost, 6); + + memcpy (resp->ether_shost, hw_addr, 6); + + resp->ether_type = eth->ether_type; + + return sizeof (struct ether_header); +} + +static ssize_t +resolve_ip (struct iphdr *ip, void *ip_resp, uint8_t ip_addr[4]) +{ + struct iphdr *resp = (struct iphdr *) ip_resp; + resp->ihl = 5; + resp->version = 4; + resp->tos = 0; + /*len updated later */ + resp->tot_len = 0x0000; + resp->id = 0; + resp->frag_off = 0; + resp->ttl = 0x40; + resp->protocol = 1; + ((uint8_t *) &resp->saddr)[0] = ip_addr[0]; + ((uint8_t *) &resp->saddr)[1] = ip_addr[1]; + ((uint8_t *) &resp->saddr)[2] = ip_addr[2]; + ((uint8_t *) &resp->saddr)[3] = ip_addr[3]; + resp->daddr = ip->saddr; + + /* resp->check = cksum (resp, sizeof (struct iphdr)); */ + + return sizeof (struct iphdr); +} + +static ssize_t +resolve_icmp (struct icmphdr *icmp, void *icmp_resp) +{ + struct icmphdr *resp = (struct icmphdr *) icmp_resp; + resp->type = 0x00; + resp->code = 0; + resp->un.echo.id = icmp->un.echo.id; + resp->un.echo.sequence = icmp->un.echo.sequence; + + /*resp->checksum = cksum (resp, sizeof (struct icmphdr)); */ + + return sizeof (struct icmphdr); +} + +int +resolve_packet (void *in_pck, ssize_t in_size, void *out_pck, + uint32_t *out_size, uint8_t ip_addr[4], uint8_t hw_addr[6]) +{ + struct ether_header *eh; + struct ether_arp *eah; + struct iphdr *ip, *ip_out; + struct icmphdr *icmp; + *out_size = 0; + + if ((in_pck == NULL) || (out_pck == NULL)) + return -1; + + eh = (struct ether_header *) in_pck; + *out_size = resolve_eth (eh, out_pck, hw_addr); + + if (eh->ether_type == 0x0608) + { + eah = (struct ether_arp *) (in_pck + *out_size); + *out_size += resolve_eth_arp (eah, out_pck + *out_size, ip_addr); + } + else if (eh->ether_type == 0x0008) + { +#ifdef ICMP_DBG + print_packet (in_pck + *out_size); +#endif + ip = (struct iphdr *) (in_pck + *out_size); + ip_out = (struct iphdr *) (out_pck + *out_size); + *out_size += resolve_ip (ip, out_pck + *out_size, ip_addr); + if (ip->protocol == 1) + { + icmp = (struct icmphdr *) (in_pck + *out_size); + *out_size += resolve_icmp (icmp, out_pck + *out_size); + ((struct icmphdr *) (out_pck + *out_size - sizeof (struct icmphdr))) + ->checksum = cksum (out_pck + *out_size - sizeof (struct icmphdr), + sizeof (struct icmphdr)); + /* payload */ + memcpy (out_pck + *out_size, in_pck + *out_size, + in_size - *out_size); + *out_size = in_size; + ip_out->tot_len = + __bswap_16 (*out_size - sizeof (struct ether_header)); + ip_out->check = cksum (ip_out, sizeof (struct iphdr)); + } + } + return 0; +} + +static ssize_t +generate_eth (struct ether_header *eh, uint8_t hw_daddr[6]) +{ + uint8_t hw_addr[6]; + int i; + for (i = 0; i < 6; i++) + { + hw_addr[i] = 'a'; + } + memcpy (eh->ether_shost, hw_addr, 6); + memcpy (eh->ether_dhost, hw_daddr, 6); + + eh->ether_type = 0x0008; + + return sizeof (struct ether_header); +} + +static ssize_t +generate_ip (struct iphdr *ip, uint8_t saddr[4], uint8_t daddr[4]) +{ + ip->ihl = 5; + ip->version = 4; + ip->tos = 0; + /*len updated later */ + ip->tot_len = 0x5400; + ip->id = 0; + ip->frag_off = 0; + ip->ttl = 0x40; + ip->protocol = 1; + /* saddr */ + ((uint8_t *) &ip->saddr)[0] = saddr[0]; + ((uint8_t *) &ip->saddr)[1] = saddr[1]; + ((uint8_t *) &ip->saddr)[2] = saddr[2]; + ((uint8_t *) &ip->saddr)[3] = saddr[3]; + /* daddr */ + ((uint8_t *) &ip->daddr)[0] = daddr[0]; + ((uint8_t *) &ip->daddr)[1] = daddr[1]; + ((uint8_t *) &ip->daddr)[2] = daddr[2]; + ((uint8_t *) &ip->daddr)[3] = daddr[3]; + + ip->check = cksum (ip, sizeof (struct iphdr)); + + return sizeof (struct iphdr); +} + +static ssize_t +generate_icmp (struct icmphdr *icmp, uint32_t seq) +{ + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->un.echo.id = 0; + icmp->un.echo.sequence = seq; + + return sizeof (struct icmphdr); +} + +int +generate_packet (void *pck, uint32_t *size, uint8_t saddr[4], uint8_t daddr[4], + uint8_t hw_daddr[6], uint32_t seq) +{ + struct ether_header *eh; + struct iphdr *ip; + struct icmphdr *icmp; + + *size = 0; + + eh = (struct ether_header *) pck; + *size += generate_eth (eh, hw_daddr); + + ip = (struct iphdr *) (pck + *size); + *size += generate_ip (ip, saddr, daddr); + + icmp = (struct icmphdr *) (pck + *size); + *size += generate_icmp (icmp, seq); + + ((struct icmphdr *) (pck + *size - sizeof (struct icmphdr)))->checksum = + cksum (pck + *size - sizeof (struct icmphdr), sizeof (struct icmphdr)); + + ip->tot_len = __bswap_16 (*size - sizeof (struct ether_header)); + ip->check = 0; + ip->check = cksum (ip, sizeof (struct iphdr)); + + return 0; +} + +int +generate_packet2 (void *pck, uint32_t *size, uint8_t saddr[4], + uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq, + icmpr_flow_mode_t mode) +{ + struct ether_header *eh; + struct iphdr *ip; + struct icmphdr *icmp; + + *size = 0; + + if (mode == ICMPR_FLOW_MODE_ETH) + { + eh = (struct ether_header *) pck; + *size += generate_eth (eh, hw_daddr); + } + + ip = (struct iphdr *) (pck + *size); + *size += generate_ip (ip, saddr, daddr); + + icmp = (struct icmphdr *) (pck + *size); + *size += generate_icmp (icmp, seq); + + ((struct icmphdr *) (pck + *size - sizeof (struct icmphdr)))->checksum = + cksum (pck + *size - sizeof (struct icmphdr), sizeof (struct icmphdr)); + + ip->tot_len = __bswap_16 (*size - sizeof (struct ether_header)); + ip->check = 0; + ip->check = cksum (ip, sizeof (struct iphdr)); + + return 0; +} + +#define GET_HEADER(out, hdr, src, off) \ + do \ + { \ + out = (hdr *) (src + off); \ + off += sizeof (hdr); \ + } \ + while (0) + +int +resolve_packet_zero_copy (void *pck, uint32_t *size, uint8_t ip_addr[4], + uint8_t hw_addr[6]) +{ + struct ether_header *eh; + struct ether_arp *eah; + struct iphdr *ip; + struct icmphdr *icmp; + uint32_t offset = 0; + + if (pck == NULL) + return 0; + + GET_HEADER (eh, struct ether_header, pck, offset); + + memcpy (eh->ether_dhost, eh->ether_shost, 6); + memcpy (eh->ether_shost, hw_addr, 6); + + if (eh->ether_type == 0x0608) + { + GET_HEADER (eah, struct ether_arp, pck, offset); + struct arphdr *arp = &eah->ea_hdr; + + arp->ar_hrd = __bswap_16 (ARPHRD_ETHER); + arp->ar_pro = __bswap_16 (0x0800); + + arp->ar_hln = 6; + arp->ar_pln = 4; + + arp->ar_op = __bswap_16 (ARPOP_REPLY); + + memcpy (eah->arp_tha, eah->arp_sha, 6); + memcpy (eah->arp_tpa, eah->arp_spa, 4); + + memcpy (eah->arp_sha, eh->ether_shost, 6); + memcpy (eah->arp_spa, ip_addr, 4); + } + + else if (eh->ether_type == 0x0008) + { + GET_HEADER (ip, struct iphdr, pck, offset); + + if (ip->protocol == 1) + { + ip->ihl = 5; + ip->version = 4; + ip->tos = 0; + ip->tot_len = 0x0000; + ip->id = 0; + ip->frag_off = 0; + ip->ttl = 0x40; + ip->protocol = 1; + ip->check = 0x0000; + ip->daddr = ip->saddr; + ((uint8_t *) &ip->saddr)[0] = ip_addr[0]; + ((uint8_t *) &ip->saddr)[1] = ip_addr[1]; + ((uint8_t *) &ip->saddr)[2] = ip_addr[2]; + ((uint8_t *) &ip->saddr)[3] = ip_addr[3]; + + GET_HEADER (icmp, struct icmphdr, pck, offset); + + icmp->type = 0x00; + icmp->code = 0; + icmp->checksum = cksum (icmp, sizeof (struct icmphdr)); + + /* rest is payload */ + offset = *size; + + ip->tot_len = __bswap_16 (offset - sizeof (struct ether_header)); + ip->check = cksum (ip, sizeof (struct iphdr)); + } + } + + assert (offset == *size && "unsupported protocol"); + return 0; +} + +int +resolve_packet_zero_copy_add_encap (void **pck_, uint32_t *size, + uint8_t ip_addr[4]) +{ + struct ether_header *eh; + struct iphdr *ip; + struct icmphdr *icmp; + int32_t offset = 0; + uint16_t encap_size = sizeof (struct ether_header); + void *pck = *pck_; + + if (pck == NULL) + return 0; + + *pck_ -= encap_size; + offset -= encap_size; + + GET_HEADER (eh, struct ether_header, pck, offset); + + uint8_t hw_daddr[6]; + memset (hw_daddr, 0, sizeof (uint8_t) * 6); + + generate_eth (eh, hw_daddr); + + if (eh->ether_type == 0x0008) + { + GET_HEADER (ip, struct iphdr, pck, offset); + + if (ip->protocol == 1) + { + ip->ihl = 5; + ip->version = 4; + ip->tos = 0; + ip->tot_len = 0x0000; + ip->id = 0; + ip->frag_off = 0; + ip->ttl = 0x40; + ip->protocol = 1; + ip->check = 0x0000; + ip->daddr = ip->saddr; + ((uint8_t *) &ip->saddr)[0] = ip_addr[0]; + ((uint8_t *) &ip->saddr)[1] = ip_addr[1]; + ((uint8_t *) &ip->saddr)[2] = ip_addr[2]; + ((uint8_t *) &ip->saddr)[3] = ip_addr[3]; + + GET_HEADER (icmp, struct icmphdr, pck, offset); + + icmp->type = 0x00; + icmp->code = 0; + icmp->checksum = cksum (icmp, sizeof (struct icmphdr)); + + /* rest is payload */ + offset = *size; + + ip->tot_len = __bswap_16 (offset - sizeof (struct ether_header)); + ip->check = cksum (ip, sizeof (struct iphdr)); + } + } + + offset += encap_size; + + assert (offset != *size && + "new packet length must be increased by encap size"); + + /* overwrite packet size */ + *size = offset; + + return 0; +} diff --git a/extras/libmemif/examples/common/icmp_proto.h b/extras/libmemif/examples/common/icmp_proto.h new file mode 100644 index 00000000000..e346a3b13f7 --- /dev/null +++ b/extras/libmemif/examples/common/icmp_proto.h @@ -0,0 +1,48 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2017 Cisco and/or its affiliates. + * 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. + *------------------------------------------------------------------ + */ + +#ifndef _ICMP_PROTO_H_ +#define _ICMP_PROTO_H_ + +typedef enum +{ + ICMPR_FLOW_MODE_ETH = 0, + ICMPR_FLOW_MODE_IP, +} icmpr_flow_mode_t; + +int resolve_packet (void *in_pck, ssize_t in_size, void *out_pck, + uint32_t *out_size, uint8_t ip_addr[4], + uint8_t hw_addr[6]); + +/* resolve packet in place */ +int resolve_packet_zero_copy (void *pck, uint32_t *size, uint8_t ip_addr[4], + uint8_t hw_addr[6]); + +/* resolve packet in place and add eth encap */ +int resolve_packet_zero_copy_add_encap (void **pck, uint32_t *size, + uint8_t ip_addr[4]); + +int generate_packet (void *pck, uint32_t *size, uint8_t saddr[4], + uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq); + +int generate_packet2 (void *pck, uint32_t *size, uint8_t saddr[4], + uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq, + icmpr_flow_mode_t); + +int print_packet (void *pck); + +#endif /* _ICMP_PROTO_H_ */ diff --git a/extras/libmemif/examples/common/packet_handler.c b/extras/libmemif/examples/common/packet_handler.c new file mode 100644 index 00000000000..705cc728a36 --- /dev/null +++ b/extras/libmemif/examples/common/packet_handler.c @@ -0,0 +1,65 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2020 Cisco and/or its affiliates. + * 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 <common.h> +#include <icmp_proto.h> + +/* reply with the same data */ +int +basic_packet_handler (memif_connection_t *c) +{ + int i; + memif_buffer_t *dest, *src; + + /* in case of zero-copy the tx_buf_num will be zero, so the loop body won't + * execute */ + for (i = 0; i < c->tx_buf_num; i++) + { + memcpy (c->tx_bufs[i].data, c->rx_bufs[i].data, c->rx_bufs[i].len); + } + + return 0; +} + +/* ICMPv4 and ARP handler */ +int +icmp_packet_handler (memif_connection_t *c) +{ + int i; + memif_buffer_t *dest, *src; + + /* if tx_buf_num > 0 we use non-zero-copy mode */ + if (c->tx_buf_num > 0) + { + for (i = 0; i < c->tx_buf_num; i++) + { + resolve_packet (c->rx_bufs[i].data, c->rx_bufs[i].len, + c->tx_bufs[i].data, &c->tx_bufs[i].len, c->ip_addr, + c->hw_addr); + } + } + else + { + for (i = 0; i < c->rx_buf_num; i++) + { + resolve_packet_zero_copy (c->rx_bufs[i].data, &c->rx_bufs[i].len, + c->ip_addr, c->hw_addr); + } + } + + return 0; +}
\ No newline at end of file diff --git a/extras/libmemif/examples/common/responder.c b/extras/libmemif/examples/common/responder.c new file mode 100644 index 00000000000..e0fa9e35b08 --- /dev/null +++ b/extras/libmemif/examples/common/responder.c @@ -0,0 +1,172 @@ +#include <common.h> + +int +responder (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ + memif_connection_t *c = (memif_connection_t *) private_ctx; + int err, i; + uint16_t tx; + + /* receive packets from the shared memory */ + err = memif_rx_burst (conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &c->rx_buf_num); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_rx_burst: %s", memif_strerror (err)); + return err; + } + + do + { + /* allocate tx buffers */ + err = memif_buffer_alloc (conn, qid, c->tx_bufs, c->rx_buf_num, + &c->tx_buf_num, 2048); + /* suppress full ring error MEMIF_ERR_NOBUF_RING */ + if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING) + { + INFO ("memif_buffer_alloc: %s", memif_strerror (err)); + goto error; + } + + /* Process the packets */ + if (c->packet_handler == NULL) + { + INFO ("Missing packet handler"); + goto error; + } + err = c->packet_handler (c); + if (err != 0) + { + INFO ("packet handler error: %d", err); + goto error; + } + /* Done processing packets */ + + /* refill the queue */ + err = memif_refill_queue (conn, qid, c->tx_buf_num, 0); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_refill_queue: %s", memif_strerror (err)); + goto error; + } + c->rx_buf_num -= c->tx_buf_num; + + err = memif_tx_burst (conn, qid, c->tx_bufs, c->tx_buf_num, &tx); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s", memif_strerror (err)); + goto error; + } + c->tx_buf_num -= tx; + + /* This should never happen */ + if (c->tx_buf_num != 0) + { + INFO ("memif_tx_burst failed to send all allocated buffers."); + goto error; + } + } + while (c->rx_buf_num > 0); + + return 0; + +error: + err = memif_refill_queue (conn, qid, c->rx_buf_num, 0); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_refill_queue: %s", memif_strerror (err)); + return err; + } + c->rx_buf_num = 0; + + return -1; +} + +int +responder_zero_copy (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ + memif_connection_t *c = (memif_connection_t *) private_ctx; + int err, i; + uint16_t tx, tx2; + + /* receive packets from the shared memory */ + err = memif_rx_burst (conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &c->rx_buf_num); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_rx_burst: %s", memif_strerror (err)); + return err; + } + + do + { + /* Note that in zero copy memif_buffer_alloc is not part of respond + process, + * instead rx buffers are used directly using memif_buffer_enq_tx. + * / + + /* Process the packets */ + if (c->packet_handler == NULL) + { + INFO ("Missing packet handler"); + goto error; + } + err = c->packet_handler (c); + if (err != 0) + { + INFO ("packet handler error: %d", err); + goto error; + } + /* Done processing packets */ + + /* Swap rx and tx buffers, swapped tx buffers are considered allocated + * and are ready to be transmitted. Notice that the buffers are swapped + * only in memif driver and locally remain in rx_bufs queue. + */ + err = memif_buffer_enq_tx (conn, qid, c->rx_bufs, c->rx_buf_num, &tx); + /* suppress full ring error MEMIF_ERR_NOBUF_RING */ + if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING) + { + INFO ("memif_buffer_alloc: %s", memif_strerror (err)); + goto error; + } + + /* refill the queue */ + err = memif_refill_queue (conn, qid, tx, 0); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_refill_queue: %s", memif_strerror (err)); + goto error; + } + c->rx_buf_num -= tx; + + /* Notice that we send from rx_bufs as the buffers were only swapped + * internally in memif driver */ + err = memif_tx_burst (conn, qid, c->rx_bufs, tx, &tx2); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s", memif_strerror (err)); + goto error; + } + tx -= tx2; + + /* This should never happen */ + if (tx != 0) + { + INFO ("memif_tx_burst failed to send all allocated buffers."); + goto error; + } + } + while (c->rx_buf_num > 0); + + return 0; + +error: + err = memif_refill_queue (conn, qid, c->rx_buf_num, 0); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_refill_queue: %s", memif_strerror (err)); + return err; + } + c->rx_buf_num = 0; + + return -1; +}
\ No newline at end of file diff --git a/extras/libmemif/examples/common/sender.c b/extras/libmemif/examples/common/sender.c new file mode 100644 index 00000000000..bad926f7a16 --- /dev/null +++ b/extras/libmemif/examples/common/sender.c @@ -0,0 +1,55 @@ +#include <common.h> + +int +send_packets (memif_connection_t *c, uint16_t qid, + packet_generator_t *generator, uint32_t num_pkts, + uint16_t max_pkt_size) +{ + int err, i; + uint16_t tx; + + do + { + err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, + num_pkts > MAX_MEMIF_BUFS ? MAX_MEMIF_BUFS : + num_pkts, + &c->tx_buf_num, max_pkt_size); + /* suppress full ring error MEMIF_ERR_NOBUF_RING */ + if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING) + { + INFO ("memif_buffer_alloc: %s", memif_strerror (err)); + goto error; + } + + /* generate packet inside allocated buffers */ + err = generator (c, num_pkts); + if (err != 0) + { + INFO ("paclet generator error: %d", err); + goto error; + } + + err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &tx); + if (err != MEMIF_ERR_SUCCESS) + { + INFO ("memif_tx_burst: %s", memif_strerror (err)); + goto error; + } + c->tx_buf_num -= tx; + + /* Should never happen... */ + if (c->tx_buf_num > 0) + { + INFO ("Failed to send allocated packets"); + goto error; + } + num_pkts -= tx; + } + while (num_pkts > 0); + + return 0; + +error: + /* TODO: free alloocated tx buffers */ + return -1; +}
\ No newline at end of file |