├── INSTALL ├── Makefile ├── README ├── doc └── netflow_testbed.png ├── in.h ├── netflow-display.c ├── netflow-display.h ├── netflow-export.c ├── netflow-export.h ├── netflow-init.c ├── netflow-init.h ├── netflow-main.c ├── netflow-main.h ├── probe.c ├── probe.h ├── rte_table_netflow.c └── rte_table_netflow.h /INSTALL: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | modprobe uio 4 | 5 | DPDK=/root/dpdk 6 | 7 | echo "Insert new igb_uio.ko" 8 | insmod $DPDK/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko 9 | 10 | $DPDK/tools/dpdk_nic_bind.py --status 11 | 12 | echo "Bind which interface?" 13 | read ifname 14 | 15 | $DPDK/tools/dpdk_nic_bind.py --bind=igb_uio $ifname 16 | $DPDK/tools/dpdk_nic_bind.py --status 17 | 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2014 Choonho Son All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ifeq ($(RTE_SDK),) 33 | $(error "Please define RTE_SDK environment variable") 34 | endif 35 | 36 | # Default target, can be overriden by command line or environment 37 | RTE_TARGET ?= x86_64-native-linuxapp-gcc 38 | 39 | include $(RTE_SDK)/mk/rte.vars.mk 40 | 41 | # binary name 42 | APP = dprobe 43 | 44 | # all source are stored in SRCS-y 45 | SRCS-y := netflow-main.c \ 46 | netflow-display.c netflow-init.c probe.c rte_table_netflow.c \ 47 | netflow-export.c 48 | 49 | CFLAGS += -O3 -g 50 | #CFLAGS += $(WERROR_FLAGS) 51 | 52 | include $(RTE_SDK)/mk/rte.extapp.mk 53 | 54 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | = Changelog = 2 | 3 | = DPDK Basic = 4 | Before using DPDK, you need to load DPDK kernel modules (uio, igb_uio). 5 | Commands: 6 | modprobe uio 7 | insmod ${DPDK}/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko 8 | 9 | After load uio, igb_uio, unbind network device driver from ixgbe to igb_uio. 10 | commands(if you want to unbind interface card p2p1): 11 | python ${DPDK}/tools/dpdk_nic_bind.py --bind=igb_uio p2p1 12 | 13 | = Build = 14 | export RTE_SDK= 15 | export RTE_TARGET=x86_64-native-linuxapp-gcc 16 | 17 | make 18 | 19 | To use multiqueues, configure different rth_eth_conf. 20 | File: netflow-init.h 21 | 22 | In 1/10G Ethernet(ixgbe), rss_hf = ETH_RSS_IPV4, 23 | In 40G Ethernet(i40e), rss_hf = ETH_RSS_NONF_IPV4_UDP | ETH_RSS_NONF_IPV4_TCP, 24 | 25 | code: 26 | static const struct rte_eth_conf port_conf = { 27 | .rxmode = { 28 | .mq_mode = ETH_MQ_RX_RSS, 29 | .split_hdr_size = 0, 30 | .header_split = 0, /**< Header Split disabled */ 31 | .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 32 | .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 33 | .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 34 | .hw_strip_crc = 0, /**< CRC stripped by hardware */ 35 | }, 36 | .rx_adv_conf = { 37 | .rss_conf = { 38 | .rss_key = NULL, 39 | .rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6, /* 1/10G RSS offload features */ 40 | //.rss_hf = ETH_RSS_NONF_IPV4_UDP | 41 | // ETH_RSS_NONF_IPV4_TCP, /* 40G RSS offload features */ 42 | }, 43 | }, 44 | .txmode = { 45 | .mq_mode = ETH_MQ_TX_NONE, 46 | }, 47 | }; 48 | 49 | 50 | = Run = 51 | 52 | To run, command line interpreter, run 2 threads 53 | ex) 2 lcore 54 | ./build/dprobe -c 0x3 -n 2 -- -p 0x1 -H 127.0.0.1 -P 2055 -q 2 55 | 56 | -H : Netflow Collector IP 57 | -P : Netflow Collector Port Number 58 | -q : Number of Receive queues 59 | 60 | ./build/dprobe -c 0x15 -n 4 -- -m "2:0.0,4:0.1" -q 2 61 | desc: lcore(2) processes port(0) queue(0) 62 | lcore(4) processes port(0) queue(1) 63 | 64 | = Reference = 65 | * DPDK build : http://sunshout.tistory.com/1556 66 | 67 | -------------------------------------------------------------------------------- /doc/netflow_testbed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/triplekill/netflow-dpdk/4573e35c2fd091e207496bc67d2b78036fc47156/doc/netflow_testbed.png -------------------------------------------------------------------------------- /in.h: -------------------------------------------------------------------------------- 1 | 2 | /* POSIX.1g specifies this type name for the `sa_family' member. */ 3 | typedef unsigned short int sa_family_t; 4 | 5 | /* This macro is used to declare the initial common members 6 | of the data types used for socket addresses, `struct sockaddr', 7 | `struct sockaddr_in', `struct sockaddr_un', etc. */ 8 | 9 | #define __SOCKADDR_COMMON(sa_prefix) \ 10 | sa_family_t sa_prefix##family 11 | 12 | #define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int)) 13 | 14 | 15 | 16 | /* Type to represent a port. */ 17 | typedef uint16_t in_port_t; 18 | 19 | /* Internet address. */ 20 | typedef uint32_t in_addr_t; 21 | struct in_addr 22 | { 23 | in_addr_t s_addr; 24 | }; 25 | 26 | /* Structure describing an Internet socket address. */ 27 | struct sockaddr_in 28 | { 29 | __SOCKADDR_COMMON (sin_); 30 | in_port_t sin_port; /* Port number. */ 31 | struct in_addr sin_addr; /* Internet address. */ 32 | 33 | /* Pad to size of `struct sockaddr'. */ 34 | unsigned char sin_zero[sizeof (struct sockaddr) - 35 | __SOCKADDR_COMMON_SIZE - 36 | sizeof (in_port_t) - 37 | sizeof (struct in_addr)]; 38 | }; 39 | 40 | 41 | -------------------------------------------------------------------------------- /netflow-display.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include "netflow-display.h" 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include "probe.h" 40 | #include "netflow-logs.h" 41 | 42 | extern probe_t probe; 43 | 44 | void 45 | netflow_logo(int row, int col, const char * appname) 46 | { 47 | int i; 48 | static const char * logo[] = { 49 | "", 50 | "# # ##### ####### ###### # #### # # #", 51 | "## # # # # # # # # # # #", 52 | "# # # # # # # # # # # # #", 53 | "# # # ##### # ###### # # # # # # #", 54 | "# # # # # # # # # # # # #", 55 | "# ## # # # # # # # # # #", 56 | "# # ##### # # ###### #### # #", 57 | NULL 58 | }; 59 | 60 | for(i=0, row++; logo[i] != NULL; i++) 61 | printf("%s\n", logo[i]); 62 | } 63 | 64 | void 65 | clrscr() 66 | { 67 | int ret; 68 | const char* CLEAR_SCREE_ANSI = "\e[1;1H\e[2J"; 69 | ret = write(STDOUT_FILENO,CLEAR_SCREE_ANSI,12); 70 | } 71 | 72 | void 73 | netflow_print(int signo) 74 | { 75 | int i; 76 | port_info_t *info; 77 | printf("\n\n\n"); 78 | NETFLOW_DISPLAY(INFO, "############ Statistics ###############\n"); 79 | for (i = 0; i < probe.nb_ports; i++) { 80 | info = &probe.info[i]; 81 | NETFLOW_DISPLAY(INFO, "+Processing(Port: %d)\n", i); 82 | NETFLOW_DISPLAY(INFO, " +---ARP : %" PRIu64 "\n", info->stats.arp_pkts); 83 | NETFLOW_DISPLAY(INFO, " +---IPv4: %" PRIu64 "\n", info->stats.ip_pkts); 84 | NETFLOW_DISPLAY(INFO, " +---IPv6: %" PRIu64 "\n", info->stats.ipv6_pkts); 85 | 86 | /* log ethernet stat */ 87 | rte_eth_stats_get(i, &info->port_stats); 88 | NETFLOW_DISPLAY(INFO, "+Ethernet Stats(Port: %d)\n", i); 89 | NETFLOW_DISPLAY(INFO, " +---ipackets: %" PRIu64 "\n", info->port_stats.ipackets - info->init_stats.ipackets); 90 | NETFLOW_DISPLAY(INFO, " +---ibytes : %" PRIu64 "\n", info->port_stats.ibytes - info->init_stats.ibytes); 91 | NETFLOW_DISPLAY(INFO, " +---imissed : %" PRIu64 "\n", info->port_stats.imissed - info->init_stats.imissed); 92 | } 93 | 94 | exit(1); 95 | } 96 | 97 | -------------------------------------------------------------------------------- /netflow-display.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETFLOW_DISPLAY_H_ 2 | #define __NETFLOW_DISPLAY_H_ 3 | 4 | void netflow_logo(int, int, const char *); 5 | void netflow_print(int); 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /netflow-export.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include "probe.h" 38 | #include "rte_table_netflow.h" 39 | 40 | #include 41 | 42 | #include "netflow-export.h" 43 | 44 | extern probe_t probe; 45 | 46 | /* Global Variable */ 47 | static struct timeval initialSniffTime; 48 | static struct timeval actTime; 49 | 50 | uint8_t engineType, engineId; 51 | uint16_t sampleRate; 52 | uint32_t flow_sequence; 53 | 54 | NetFlow5Record theV5Flow; 55 | 56 | void netflow_export_init() { 57 | gettimeofday(&initialSniffTime, NULL); 58 | engineType = 0; 59 | engineId = 0; 60 | sampleRate = 0; 61 | } 62 | 63 | /* ****************************************************** */ 64 | 65 | u_int32_t msTimeDiff(struct timeval end, struct timeval begin) { 66 | if((end.tv_sec == 0) && (end.tv_usec == 0)) 67 | return(0); 68 | else 69 | return((end.tv_sec-begin.tv_sec)*1000+(end.tv_usec-begin.tv_usec)/1000); 70 | } 71 | 72 | /******************************************************* */ 73 | 74 | void initNetFlowV5Header(NetFlow5Record *theV5Flow) { 75 | memset(&theV5Flow->flowHeader, 0, sizeof(theV5Flow->flowHeader)); 76 | 77 | theV5Flow->flowHeader.version = rte_cpu_to_be_16(5); 78 | theV5Flow->flowHeader.sysUptime = rte_cpu_to_be_32(msTimeDiff(actTime, 79 | initialSniffTime)); 80 | theV5Flow->flowHeader.unix_secs = rte_cpu_to_be_32(actTime.tv_sec); 81 | theV5Flow->flowHeader.unix_nsecs = rte_cpu_to_be_32(actTime.tv_usec/1000); 82 | /* NOTE: theV5Flow->flowHeader.flow_sequence will be filled by sendFlowData */ 83 | theV5Flow->flowHeader.engine_type = (u_int8_t)engineType; 84 | theV5Flow->flowHeader.engine_id = (u_int8_t)engineId; 85 | 86 | theV5Flow->flowHeader.sampleRate = rte_cpu_to_be_16(sampleRate); 87 | } 88 | 89 | static int exportBucketToNetflowV5(hashBucket_t* bkt, uint8_t numFlows) 90 | { 91 | theV5Flow.flowRecord[numFlows].input = 0; // TODO 92 | theV5Flow.flowRecord[numFlows].output = 0; // TODO 93 | theV5Flow.flowRecord[numFlows].srcaddr = bkt->ip_src; 94 | theV5Flow.flowRecord[numFlows].dstaddr = bkt->ip_dst; 95 | theV5Flow.flowRecord[numFlows].dPkts = rte_cpu_to_be_32(bkt->pktSent); 96 | theV5Flow.flowRecord[numFlows].dOctets = rte_cpu_to_be_32(bkt->bytesSent); 97 | theV5Flow.flowRecord[numFlows].first = rte_cpu_to_be_32(msTimeDiff(bkt->firstSeenSent, initialSniffTime)); 98 | theV5Flow.flowRecord[numFlows].last = rte_cpu_to_be_32(msTimeDiff(bkt->lastSeenSent, initialSniffTime)); 99 | theV5Flow.flowRecord[numFlows].srcport = bkt->port_src; 100 | theV5Flow.flowRecord[numFlows].dstport = bkt->port_dst; 101 | theV5Flow.flowRecord[numFlows].tos = bkt->src2dstTos; 102 | theV5Flow.flowRecord[numFlows].src_as = 0; // TODO 103 | theV5Flow.flowRecord[numFlows].dst_as = 0; // TODO 104 | theV5Flow.flowRecord[numFlows].src_mask = 0; // TODO 105 | theV5Flow.flowRecord[numFlows].dst_mask = 0; // TODO 106 | theV5Flow.flowRecord[numFlows].tcp_flags = bkt->src2dstTcpFlags; 107 | theV5Flow.flowRecord[numFlows].proto = bkt->proto; 108 | } 109 | 110 | hashBucket_t* makeNetFlowV5(hashBucket_t *list) 111 | { 112 | uint16_t num_flows = 1; 113 | hashBucket_t *temp; 114 | 115 | /* Make header */ 116 | initNetFlowV5Header(&theV5Flow); 117 | /* Make Records */ 118 | while(list != NULL) { 119 | temp = list; 120 | //printf("num_flows:%d\n", num_flows); 121 | exportBucketToNetflowV5(list, num_flows - 1); 122 | list = list->next; 123 | rte_free(temp); 124 | num_flows++; 125 | if(num_flows > V5FLOWS_PER_PAK) break; 126 | } 127 | num_flows--; 128 | theV5Flow.flowHeader.count = rte_cpu_to_be_16(num_flows); 129 | return list; 130 | } 131 | 132 | static void sendNetflowV5() 133 | { 134 | int msg_length; 135 | uint16_t record_count; 136 | 137 | theV5Flow.flowHeader.flow_sequence = rte_cpu_to_be_32(flow_sequence++); 138 | record_count = rte_cpu_to_be_16(theV5Flow.flowHeader.count); 139 | printf("record count:%d\n", record_count); 140 | msg_length = sizeof(struct flow_ver5_hdr) + record_count * sizeof(struct flow_ver5_rec); 141 | sendto(probe.collector.sockfd, (void *)&theV5Flow, msg_length, 0, (struct sockaddr *)&probe.collector.servaddr, sizeof(probe.collector.servaddr)); 142 | 143 | } 144 | 145 | static hashBucket_t* make_export(hashBucket_t *export_list) 146 | { 147 | hashBucket_t *next; 148 | uint32_t count = 0; 149 | gettimeofday(&actTime, NULL); 150 | 151 | if (5) { 152 | while (export_list != NULL) { 153 | export_list = makeNetFlowV5(export_list); 154 | sendNetflowV5(); 155 | } 156 | } 157 | printf("should be NULL(export_list:%p)\n", export_list); 158 | return export_list; 159 | } 160 | #define IDLE_TIMEOUT 60 161 | #define LIFETIME_TIMEOUT 120 162 | 163 | void process_hashtable() 164 | { 165 | //temp 166 | int pid = 0; 167 | 168 | struct rte_table_netflow *t = (struct rte_table_netflow *)probe.table[pid]; 169 | hashBucket_t *temp, *bkt; 170 | hashBucket_t *export_list = NULL; 171 | struct rte_table_hashBucket *prev_next_pointer; 172 | 173 | uint32_t i, entry, idx; 174 | uint32_t sleep_time; 175 | struct timeval curr, lastseen, firstseen; 176 | uint32_t export_count; 177 | 178 | while (1) { 179 | sleep_time = 60 - (time(NULL) % 60); /* Align minutes */ 180 | //sleep_time = 10; 181 | sleep(sleep_time); 182 | 183 | /* check hash table */ 184 | entry = t->n_entries; 185 | 186 | export_count = 0; 187 | /* loop all entry */ 188 | printf("Start of check:export list must null:%p\n", export_list); 189 | for(i = 0; i < entry; i++) { 190 | /**************************************************************** 191 | * Lock one entry (t->array[i]'s lock = t->lock[i] 192 | * 193 | * So netflow_export can use other entries 194 | ****************************************************************/ 195 | rte_spinlock_lock(&t->lock[i]); 196 | 197 | bkt = t->array[i]; 198 | if(likely(bkt == NULL)) { 199 | rte_spinlock_unlock(&t->lock[i]); 200 | continue; 201 | } 202 | 203 | /* Bucket exist */ 204 | /* lock the entry */ 205 | gettimeofday(&curr, NULL); 206 | 207 | idx = 0; 208 | while(bkt != NULL) { 209 | temp = bkt->next; 210 | /* check bucket timestamp */ 211 | lastseen = bkt->lastSeenSent; 212 | firstseen = bkt->firstSeenSent; 213 | 214 | if ( ((curr.tv_sec - lastseen.tv_sec) > IDLE_TIMEOUT) /* data doesn't send for a while */ 215 | || ((curr.tv_sec - firstseen.tv_sec) > LIFETIME_TIMEOUT) /* flow is active, but too old */ 216 | || bkt->bucket_expired > 0 ) { 217 | /* export bucket to export_list */ 218 | bkt->next = export_list; 219 | export_list = bkt; 220 | export_count++; 221 | //printf("Add to export list:%d\n", export_count); 222 | /* if first bucket is exported, we loss t->array[i] */ 223 | if (idx == 0) t->array[i] = temp; 224 | 225 | } 226 | idx++; 227 | bkt = temp; 228 | } 229 | 230 | rte_spinlock_unlock(&t->lock[i]); 231 | /*********************************************************************** 232 | * End of entry lock 233 | * release lock 234 | **********************************************************************/ 235 | } 236 | /* for each entry, check life time */ 237 | if (export_count > 0) 238 | export_list = make_export(export_list); 239 | 240 | } /* end of while */ 241 | 242 | } 243 | -------------------------------------------------------------------------------- /netflow-export.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETFLOW_EXPORT_H_ 2 | #define __NETFLOW_EXPORT_H_ 3 | 4 | void process_hashtable(); 5 | 6 | 7 | #endif 8 | 9 | -------------------------------------------------------------------------------- /netflow-init.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include "netflow-init.h" 33 | 34 | #include "probe.h" 35 | #include "rte_table_netflow.h" 36 | 37 | static void 38 | print_ethaddr(const char *name, const struct ether_addr *eth_addr) 39 | { 40 | printf ("%s%02X:%02X:%02X:%02X:%02X:%02X\n", name, 41 | eth_addr->addr_bytes[0], 42 | eth_addr->addr_bytes[1], 43 | eth_addr->addr_bytes[2], 44 | eth_addr->addr_bytes[3], 45 | eth_addr->addr_bytes[4], 46 | eth_addr->addr_bytes[5]); 47 | } 48 | 49 | #define NETFLOW_HASH_ENTRIES 4 * 1024 * 1024 50 | 51 | static void 52 | setup_netflow_table(probe_t* p) 53 | { 54 | struct rte_table_netflow_params param = { 55 | .n_entries = NETFLOW_HASH_ENTRIES, 56 | .offset = 0, 57 | .f_hash = rte_hash_crc_4byte, 58 | .seed = 0, 59 | }; 60 | 61 | 62 | int i,j; 63 | for (i = 0; i < p->nb_ports; i++) { 64 | p->table[i] = (struct rte_table_netflow *)rte_table_netflow_create(¶m, i, sizeof(hashBucket_t)); 65 | } 66 | } 67 | 68 | int 69 | init_memory(unsigned nb_mbuf, uint8_t pid, uint8_t nb_queues) 70 | { 71 | uint8_t lid; // lcore_id 72 | int sid; // socket_id 73 | int ret; 74 | uint8_t qid; // queue_id 75 | char s[64]; 76 | uint8_t i; 77 | 78 | if (numa_on) 79 | sid = rte_lcore_to_socket_id(lid); 80 | else 81 | sid = 0; 82 | 83 | /* mempool */ 84 | if (pktmbuf_pool[sid] == NULL) { 85 | snprintf(s, sizeof(s), "netflow_pool_%d", sid); 86 | pktmbuf_pool[sid] = 87 | rte_mempool_create(s, nb_mbuf, MBUF_SIZE, MEMPOOL_CACHE_SIZE, 88 | sizeof(struct rte_pktmbuf_pool_private), 89 | rte_pktmbuf_pool_init, NULL, 90 | rte_pktmbuf_init, NULL, 91 | sid, 0); 92 | if (pktmbuf_pool[sid] == NULL) 93 | rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket(%d)\n", sid); 94 | } 95 | 96 | /* mbuf pool */ 97 | for(i = 0; i < nb_queues; i++) { 98 | ret = rte_eth_rx_queue_setup(pid, i, 512, sid, &rx_conf, pktmbuf_pool[sid]); 99 | if (ret < 0) 100 | rte_exit(EXIT_FAILURE, "Failed to rx_queue_setup\n"); 101 | } 102 | ret = rte_eth_tx_queue_setup(pid, 0, 128, sid, &tx_conf); 103 | 104 | } 105 | 106 | int 107 | netflow_init(probe_t *probe) 108 | { 109 | probe->nb_ports = rte_eth_dev_count(); 110 | uint8_t pid; // port_id 111 | uint8_t ret; 112 | 113 | RTE_LOG(DEBUG, PMD, "Number of ports: %d\n", probe->nb_ports); 114 | 115 | /* init Port */ 116 | for (pid = 0; pid < probe->nb_ports; pid++) { 117 | RTE_LOG(DEBUG, PMD, "Init Port(%d)\n", pid); 118 | 119 | // param (port_id,nb_rx_queue, nb_tx_queue, ...) 120 | ret = rte_eth_dev_configure(pid, probe->nb_queues, 1, &port_conf); 121 | if (ret < 0) 122 | rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", ret, pid); 123 | 124 | rte_eth_macaddr_get(pid, &probe->ports_eth_addr[pid]); 125 | print_ethaddr("MAC address:", &probe->ports_eth_addr[pid]); 126 | 127 | /* init memory per port */ 128 | if (init_memory(NB_MBUF, pid, probe->nb_queues) < 0) 129 | rte_exit(EXIT_FAILURE, "Fail to initialize memory\n"); 130 | 131 | /* start device */ 132 | ret = rte_eth_dev_start(pid); 133 | if (ret < 0) 134 | rte_exit(EXIT_FAILURE, "Fail to start dev\n"); 135 | 136 | rte_eth_promiscuous_enable(pid); 137 | 138 | /* log ethernet init stats */ 139 | rte_eth_stats_get(pid, &probe->info[pid].init_stats); 140 | } 141 | 142 | /* netflow hash table init */ 143 | setup_netflow_table(probe); 144 | 145 | /* setup netflow collector information */ 146 | probe->collector.sockfd = socket(AF_INET, SOCK_DGRAM, 0); 147 | bzero(&probe->collector.servaddr, sizeof(probe->collector.servaddr)); 148 | probe->collector.servaddr.sin_family = AF_INET; 149 | probe->collector.servaddr.sin_addr.s_addr = inet_addr(probe->collector.addr); 150 | probe->collector.servaddr.sin_port = rte_cpu_to_be_16(probe->collector.port); 151 | 152 | 153 | printf("----------- MEMORY_SEGMENTS -----------\n"); 154 | rte_dump_physmem_layout(stdout); 155 | printf("--------- END_MEMORY_SEGMENTS ---------\n"); 156 | printf("------------ MEMORY_ZONES -------------\n"); 157 | rte_memzone_dump(stdout); 158 | printf("---------- END_MEMORY_ZONES -----------\n"); 159 | printf("---------- TAIL_QUEUES ----------------\n"); 160 | rte_dump_tailq(stdout); 161 | 162 | return 0; 163 | } 164 | -------------------------------------------------------------------------------- /netflow-init.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETFLOW_INIT_H_ 2 | #define __NETFLOW_INIT_H_ 3 | 4 | #include "probe.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NB_SOCKETS 2 14 | #define NB_MBUF 8192 15 | #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 16 | 17 | #define MEMPOOL_CACHE_SIZE 256 18 | 19 | static const struct rte_eth_conf port_conf = { 20 | .rxmode = { 21 | .mq_mode = ETH_MQ_RX_RSS, 22 | .split_hdr_size = 0, 23 | .header_split = 0, /**< Header Split disabled */ 24 | .hw_ip_checksum = 0, /**< IP checksum offload disabled */ 25 | .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 26 | .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 27 | .hw_strip_crc = 0, /**< CRC stripped by hardware */ 28 | }, 29 | .rx_adv_conf = { 30 | .rss_conf = { 31 | .rss_key = NULL, 32 | .rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6, /* 1/10G RSS offload features */ 33 | //.rss_hf = ETH_RSS_NONF_IPV4_UDP | 34 | // ETH_RSS_NONF_IPV4_TCP, /* 40G RSS offload features */ 35 | }, 36 | }, 37 | .txmode = { 38 | .mq_mode = ETH_MQ_TX_NONE, 39 | }, 40 | }; 41 | 42 | #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ 43 | #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ 44 | #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ 45 | 46 | static const struct rte_eth_rxconf rx_conf = { 47 | .rx_thresh = { 48 | .pthresh = RX_PTHRESH, 49 | .hthresh = RX_HTHRESH, 50 | .wthresh = RX_WTHRESH, 51 | }, 52 | }; 53 | 54 | #define TX_PTHRESH 36 55 | #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ 56 | #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ 57 | 58 | static const struct rte_eth_txconf tx_conf = { 59 | .tx_thresh = { 60 | .pthresh = TX_PTHRESH, 61 | .hthresh = TX_HTHRESH, 62 | .wthresh = TX_WTHRESH, 63 | }, 64 | }; 65 | 66 | static struct rte_mempool *pktmbuf_pool[NB_SOCKETS]; 67 | static int numa_on = 1; 68 | 69 | typedef struct rte_hash lookup_stuct_t; 70 | static lookup_stuct_t *netflow_V5_lookup_struct[NB_SOCKETS]; 71 | 72 | int netflow_init(probe_t *); 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /netflow-main.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include "netflow-main.h" 32 | 33 | #include 34 | #include "probe.h" 35 | #include "netflow-display.h" 36 | #include "netflow-init.h" 37 | #include "netflow-export.h" 38 | #include "netflow-logs.h" 39 | #include 40 | 41 | probe_t probe; 42 | 43 | 44 | /************************************************************************** 45 | * netflow_usage - Display the help for the command line. 46 | * 47 | * DESCRIPTION 48 | * Display the help message for the command line. 49 | * 50 | * RETURNS: N/A 51 | */ 52 | 53 | static void 54 | netflow_usage(const char *prgname) 55 | { 56 | printf("Usage: %s [EAL options] -- [-h]\n" 57 | " -m matrix for mapping ports to logical cores\n" 58 | " -q number of Queues per port\n" 59 | " -H (default:127.0.0.1)\n" 60 | " -P (default:2055)\n" 61 | " -h Display the help information\n", 62 | prgname); 63 | } 64 | 65 | static void 66 | parse_netflow_collector_host(const char *str) 67 | { 68 | sscanf(str, "%s", probe.collector.addr); 69 | } 70 | static void 71 | parse_netflow_collector_port(const char *str) 72 | { 73 | sscanf(str, "%d", &probe.collector.port); 74 | } 75 | 76 | 77 | static void 78 | parse_netflow_num_queues(const char *str) 79 | { 80 | int num; 81 | sscanf(str, "%d", &num); 82 | probe.nb_queues = num; 83 | } 84 | 85 | static void 86 | parse_netflow_l2p(const char *str) 87 | { 88 | /* str ex) "1:0.0,2:0.1" 89 | * means lcore(1) processes port(0) + qeuue(0) 90 | * lcore(2) processes port(0) + queue(1) 91 | */ 92 | char temp[64]; 93 | strcpy(temp, str); 94 | char *ptr; 95 | int lid,pid,qid; 96 | int idx=0; 97 | int lcore_count = 0; 98 | uint8_t lcore_id; 99 | 100 | ptr = strtok(temp, ","); 101 | sscanf(ptr, "%d:%d.%d", &lid, &pid, &qid); 102 | probe.l2p[idx].lcore_id = lid; 103 | probe.l2p[idx].port_id = pid; 104 | probe.l2p[idx].queue_id = qid; 105 | idx++; 106 | while (ptr = strtok(NULL, ",")) { 107 | sscanf(ptr, "%d:%d.%d", &lid, &pid, &qid); 108 | probe.l2p[idx].lcore_id = lid; 109 | probe.l2p[idx].port_id = pid; 110 | probe.l2p[idx].queue_id = qid; 111 | idx++; 112 | } 113 | RTE_LCORE_FOREACH_SLAVE(lcore_id) { 114 | lcore_count++; 115 | } 116 | if (idx != lcore_count) { 117 | NETFLOW_INIT_LOG(ERR, "ERROR: lcore_count(%d) and mapping(%d) is not match\n", --lcore_count, --idx); 118 | } 119 | } 120 | 121 | /****************************************************************************** 122 | * netflow_parse_args - Parse the argument given in the command line of the application 123 | * 124 | * DESCRIPTION 125 | * Main parsing routine for the command line. 126 | * 127 | * RETURNS: N/A 128 | */ 129 | 130 | static int 131 | netflow_parse_args(int argc, char **argv) 132 | { 133 | int opt, ret; 134 | char **argvopt; 135 | int option_index; 136 | char *prgname = argv[0]; 137 | static struct option lgopts[] = { 138 | {NULL, 0, 0, 0} 139 | }; 140 | 141 | argvopt = argv; 142 | 143 | while ((opt = getopt_long(argc, argvopt, "m:H:P:q:", 144 | lgopts, &option_index)) != EOF) { 145 | 146 | switch (opt) { 147 | case 'm': 148 | /* lcore:port.queue mapping 149 | * ex) -m "1:0.0" means lcore1 processes queueue 0 of port 0 150 | */ 151 | parse_netflow_l2p(optarg); 152 | break; 153 | case 'H': 154 | // Collector IP 155 | parse_netflow_collector_host(optarg); 156 | break; 157 | case 'P': 158 | // Collector Port 159 | parse_netflow_collector_port(optarg); 160 | break; 161 | case 'q': 162 | // Number of Queues / Port 163 | parse_netflow_num_queues(optarg); 164 | break; 165 | /* long options */ 166 | case 0: 167 | netflow_usage(prgname); 168 | return -1; 169 | 170 | default: 171 | netflow_usage(prgname); 172 | return -1; 173 | } 174 | } 175 | 176 | if (optind >= 0) 177 | argv[optind-1] = prgname; 178 | 179 | ret = optind-1; 180 | optind = 0; /* reset getopt lib */ 181 | return ret; 182 | } 183 | 184 | void init_probe(probe_t *p) 185 | { 186 | memset(p, 0, sizeof(probe)); 187 | /* set default vaule */ 188 | strcpy(p->collector.addr, "127.0.0.1"); 189 | p->collector.port = 2055; 190 | 191 | p->nb_queues = 1; 192 | } 193 | 194 | 195 | int main(int argc, char **argv) 196 | { 197 | int32_t ret; 198 | uint8_t lcore_id; 199 | 200 | /* Signal */ 201 | signal(SIGINT,(void *)netflow_print); 202 | 203 | 204 | clrscr(); 205 | // call before the rte_eal_init() 206 | (void)rte_set_application_usage_hook(netflow_usage); 207 | 208 | init_probe(&probe); 209 | 210 | netflow_logo(8, 0, NETFLOW_APP_NAME); 211 | sleep(2); 212 | 213 | ret = rte_eal_init(argc, argv); 214 | if (ret < 0) 215 | rte_exit(EXIT_FAILURE, "Failed in rte_eal_init\n"); 216 | argc -= ret; 217 | argv += ret; 218 | 219 | ret = netflow_parse_args(argc, argv); 220 | if (ret < 0) 221 | rte_exit(EXIT_FAILURE, "Invalid arguments\n"); 222 | 223 | netflow_init(&probe); 224 | 225 | RTE_LCORE_FOREACH_SLAVE(lcore_id) { 226 | rte_eal_remote_launch(launch_probe, NULL, lcore_id); 227 | } 228 | rte_delay_ms(5000); // wait for the lcores to start up 229 | 230 | // Wait for all of the cores to stop runing and exit. 231 | 232 | process_hashtable(); 233 | rte_eal_mp_wait_lcore(); 234 | 235 | return 0; 236 | } 237 | 238 | -------------------------------------------------------------------------------- /netflow-main.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETFLOW_MAIN_H_ 2 | #define __NETFLOW_MAIN_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /probe.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | 33 | #include "probe.h" 34 | 35 | 36 | extern probe_t probe; 37 | 38 | // Allocate the netflow structure for global use 39 | 40 | volatile int quit = 0; 41 | 42 | /**************************************************************************//** 43 | * 44 | * packet_type - Examine a packet and return the type of packet 45 | * 46 | * DESCRIPTION 47 | * Examine a packet and return the type of packet. 48 | * the packet. 49 | * 50 | * RETURNS: N/A 51 | * 52 | * SEE ALSO: 53 | */ 54 | 55 | static __inline__ pktType_e 56 | packet_type( struct rte_mbuf * m ) 57 | { 58 | pktType_e ret; 59 | struct ether_hdr *eth; 60 | 61 | eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 62 | 63 | ret = ntohs(eth->ether_type); 64 | 65 | return ret; 66 | } 67 | 68 | #define PRINT_IP(x) printf("%d.%d.%d.%d", (x&0x000000ff), (x&0x0000ff00)>>8, (x&0x00ff0000)>>16, (x&0xff000000)>>24) 69 | 70 | void 71 | print_ipv4(struct ipv4_hdr *ip) 72 | { 73 | PRINT_IP(ip->src_addr); 74 | printf("-(%d)->", ip->next_proto_id); 75 | PRINT_IP(ip->dst_addr); 76 | printf("\n"); 77 | } 78 | void 79 | print_flow(union rte_table_netflow_key *k) 80 | { 81 | PRINT_IP(k->ip_src); 82 | printf(" (%d) -[%d]-> (%d) ", ntohs(k->port_src), k->proto, ntohs(k->port_dst)); 83 | PRINT_IP(k->ip_dst); 84 | printf("\n"); 85 | } 86 | 87 | /**************************************************************************** 88 | * 89 | */ 90 | void 91 | process_ipv4(struct rte_mbuf * m, int pid, int vlan) 92 | { 93 | port_info_t *info = &probe.info[pid]; 94 | struct rte_table_netflow *t = (struct rte_table_netflow *)probe.table[pid]; 95 | hashBucket_t *bkt; 96 | int key_found=0; 97 | char proto; 98 | struct ether_hdr *eth = rte_pktmbuf_mtod(m, struct ether_hdr *); 99 | struct ipv4_hdr *ip = (struct ipv4_hdr *)ð[1]; 100 | struct tcp_hdr *tcp; 101 | struct udp_hdr *udp; 102 | 103 | union rte_table_netflow_key k; 104 | 105 | uint32_t init_val; 106 | 107 | /* Adjust for a vlan header if present */ 108 | if (vlan) 109 | ip = (struct ipv4_hdr *)((char *)ip + sizeof(struct vlan_hdr)); 110 | 111 | k.ip_src = ip->src_addr; 112 | k.ip_dst = ip->dst_addr; 113 | k.proto = ip->next_proto_id; 114 | k.pad0 = 0; 115 | k.pad1 = 0; 116 | k.vlanId = vlan; 117 | 118 | //print_ipv4(ip); 119 | // based on proto, TCP/UDP/ICMP... 120 | switch(ip->next_proto_id) { 121 | case IPPROTO_UDP: 122 | udp = (struct udp_hdr *)((unsigned char*)ip + sizeof(struct ipv4_hdr)); 123 | k.port_src = udp->src_port; 124 | k.port_dst = udp->dst_port; 125 | break; 126 | 127 | case IPPROTO_TCP: 128 | tcp = (struct tcp_hdr *)((unsigned char*)ip + sizeof(struct ipv4_hdr)); 129 | k.port_src = tcp->src_port; 130 | k.port_dst = tcp->dst_port; 131 | break; 132 | 133 | default: 134 | break; 135 | } 136 | rte_table_netflow_entry_add(t, &k, ip, &key_found, &bkt); 137 | 138 | //print_flow(&k); 139 | //TODO 140 | // 1) decode flow header 141 | // 2) pkt to hash 142 | //printf("%" PRIu32 "\n", init_val); 143 | // 3) process hash table (export flows) 144 | } 145 | 146 | 147 | /**************************************************************************** 148 | * 149 | * packet_classify - Examine a packet and classify it for statistics 150 | * 151 | * DESCRIPTION 152 | * Examine a packet and determine its type along with counting statistics around 153 | * the packet. 154 | * 155 | * RETURNS: N/A 156 | * 157 | * SEE ALSO: 158 | */ 159 | #define FCS_SIZE 4 160 | 161 | static void 162 | packet_classify( struct rte_mbuf * m, int pid ) 163 | { 164 | port_info_t * info = &probe.info[pid]; 165 | int plen = (m->pkt_len + FCS_SIZE); 166 | pktType_e pType; 167 | 168 | pType = packet_type(m); 169 | 170 | switch((int)pType) { 171 | case ETHER_TYPE_ARP: info->stats.arp_pkts++; printf("arp\n"); break; 172 | case ETHER_TYPE_IPv4: info->stats.ip_pkts++; process_ipv4(m, pid, 0); break; 173 | case ETHER_TYPE_IPv6: info->stats.ipv6_pkts++; break; 174 | case ETHER_TYPE_VLAN: info->stats.vlan_pkts++; break; 175 | case UNKNOWN_PACKET: /* FALL THRU */ 176 | default: break; 177 | } 178 | 179 | } 180 | 181 | 182 | /************************************************************* 183 | * packet classify - Classify a set of packets in one call 184 | * 185 | * DESCRIPTION 186 | * Classify a list of packets and to improve clasify peformance. 187 | * 188 | * Return: N/A 189 | */ 190 | #define PREFETCH_OFFSET 3 191 | static __inline__ void 192 | packet_classify_bulk(struct rte_mbuf **pkts, int nb_rx, int pid) 193 | { 194 | int j; 195 | /* Prefetch first packets */ 196 | for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) 197 | rte_prefetch0(rte_pktmbuf_mtod(pkts[j], void *)); 198 | 199 | /* Prefetch and handle already prefetched packets */ 200 | for (j = 0; j < (nb_rx-PREFETCH_OFFSET); j++) { 201 | rte_prefetch0(rte_pktmbuf_mtod(pkts[j + PREFETCH_OFFSET], void *)); 202 | packet_classify(pkts[j], pid); 203 | } 204 | 205 | /* TODO */ 206 | // Additional processing like DPI 207 | 208 | /* Handle remaining prefetched packets */ 209 | for (; j < nb_rx; j++) 210 | packet_classify(pkts[j], pid); 211 | 212 | } 213 | 214 | int 215 | launch_probe(__attribute__((unused)) void *arg) 216 | { 217 | uint8_t lcore_id = rte_lcore_id(); 218 | uint8_t nb_rx, pid, qid, i, j; 219 | struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 220 | struct rte_mbuf *m; 221 | 222 | printf("## lcore_id:%d\n", lcore_id); 223 | /* find l2p mapping */ 224 | l2p_t *l2p; 225 | for (i = 0; i <= _MAX_LCORE; i++) { 226 | l2p = &probe.l2p[i]; 227 | if (l2p->lcore_id == lcore_id) { 228 | pid = l2p->port_id; 229 | qid = l2p->queue_id; 230 | break; 231 | } 232 | } 233 | printf("lcore ID:%d\n", lcore_id); 234 | printf("port ID:%d\n", pid); 235 | printf("queue ID:%d\n", qid); 236 | 237 | while(!quit) { 238 | // Read packet from RX Queue 239 | // param0: port ID 240 | // param1: queue ID 241 | nb_rx = rte_eth_rx_burst(pid, qid, pkts_burst, MAX_PKT_BURST); 242 | if (unlikely(nb_rx == 0)) continue; 243 | 244 | //printf("lcore(%d) nb_packet(%d)\n", lcore_id, nb_rx); 245 | // classify the packets 246 | packet_classify_bulk(pkts_burst, nb_rx, pid); 247 | 248 | // free the packets 249 | for(j = 0; j < nb_rx; j++) 250 | rte_pktmbuf_free(pkts_burst[j]); 251 | 252 | } 253 | return 0; 254 | } 255 | -------------------------------------------------------------------------------- /probe.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROBE_H_ 2 | #define __PROBE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "rte_table_netflow.h" 17 | #include "in.h" 18 | 19 | #define NETFLOW_APP_NAME "Netflow DPDK" 20 | 21 | #define MAX_PKT_BURST 16 22 | 23 | typedef struct rte_eth_stats eth_stats_t; 24 | 25 | typedef enum { PACKET_CONSUMED = 0, UNKNOWN_PACKET = 0xEEEE, DROP_PACKET = 0xFFFE, FREE_PACKET = 0xFFFF } pktType_e; 26 | 27 | typedef struct pkt_stats_s { 28 | uint64_t arp_pkts; /**< Number of ARP packets received */ 29 | uint64_t echo_pkts; /**< Number of ICMP echo requests received */ 30 | uint64_t ip_pkts; /**< Number of IPv4 packets received */ 31 | uint64_t ipv6_pkts; /**< Number of IPv6 packets received */ 32 | uint64_t vlan_pkts; /**< Number of VLAN packets received */ 33 | uint64_t dropped_pkts; /**< Hyperscan dropped packets */ 34 | uint64_t unknown_pkts; /**< Number of Unknown packets */ 35 | uint64_t tx_failed; /**< Transmits that failed to send */ 36 | } pkt_stats_t; 37 | 38 | 39 | typedef struct port_info_s { 40 | uint16_t pid; /**< Port ID value */ 41 | 42 | pkt_stats_t stats; /**< Statistics for a number of stats */ 43 | 44 | eth_stats_t init_stats; /**< Initial packet statistics */ 45 | eth_stats_t port_stats; /**< current port statistics */ 46 | eth_stats_t rate_stats; /**< current packet rate statistics */ 47 | 48 | struct rte_eth_link link; /**< Link information link speed and duplex */ 49 | } port_info_t; 50 | 51 | //##### Temp ##### 52 | #define _RTE_MAX_ETHPORTS 2 53 | #define _NB_SOCKETS 2 54 | #define _MAX_LCORE 8 55 | 56 | /* Netflow Collector information */ 57 | typedef struct collector_s { 58 | char addr[16]; 59 | int port; 60 | int sockfd; 61 | struct sockaddr_in servaddr; 62 | } collector_t; 63 | 64 | /* lcore, port, queue mapping table */ 65 | typedef struct l2p_s { 66 | uint8_t lcore_id; 67 | uint8_t port_id; 68 | uint8_t queue_id; 69 | } l2p_t; 70 | 71 | typedef struct probe_s { 72 | //struct cmdline *cli; 73 | char* *hostname; /* hostname */ 74 | uint8_t nb_ports; 75 | uint8_t nb_queues; 76 | uint16_t nb_rxd; 77 | uint16_t nb_txd; 78 | uint16_t portNum; 79 | struct ether_addr ports_eth_addr[_RTE_MAX_ETHPORTS]; 80 | 81 | // Netflow collector 82 | collector_t collector; 83 | 84 | // port to lcore mapping 85 | l2p_t l2p[_MAX_LCORE]; 86 | 87 | /* Statistics */ 88 | port_info_t info[_RTE_MAX_ETHPORTS]; /**< Port Information */ 89 | 90 | /* hash table */ 91 | //struct rte_table_netflow my_table[2]; 92 | struct rte_table_netflow *table[_RTE_MAX_ETHPORTS]; 93 | 94 | } probe_t; 95 | 96 | 97 | extern int launch_probe(__attribute__ ((unused)) void * arg); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /rte_table_netflow.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2014, Choonho Son choonho.som@gmail.com 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "rte_table_netflow.h" 44 | 45 | void * 46 | rte_table_netflow_create(void *params, int socket_id, uint32_t entry_size) 47 | { 48 | struct rte_table_netflow_params *p = 49 | (struct rte_table_netflow_params *) params; 50 | 51 | struct rte_table_netflow *t; 52 | uint32_t total_cl_size, total_size; 53 | uint32_t i; 54 | 55 | if (p->n_entries > MAX_ENTRY) { 56 | RTE_LOG(ERR, TABLE, "Entry is large than MAX_ENTRY(%d)\n", (uint32_t)MAX_ENTRY); 57 | p->n_entries = MAX_ENTRY; 58 | } 59 | 60 | /* Check input parameters */ 61 | if ((p == NULL) || 62 | (p->n_entries == 0) || 63 | (!rte_is_power_of_2(p->n_entries)) ) { 64 | return NULL; 65 | } 66 | 67 | /* Memory allocation */ 68 | total_cl_size = (sizeof(struct rte_table_netflow) + 69 | CACHE_LINE_SIZE) / CACHE_LINE_SIZE; 70 | total_cl_size += (p->n_entries * sizeof(hashBucket_t*) + 71 | CACHE_LINE_SIZE) / CACHE_LINE_SIZE; 72 | total_size = total_cl_size * CACHE_LINE_SIZE; 73 | t = rte_zmalloc_socket("TABLE", total_size, CACHE_LINE_SIZE, socket_id); 74 | if (t == NULL) { 75 | RTE_LOG(ERR, TABLE, 76 | "%s: Cannot allocate %u bytes for netflow table\n", 77 | __func__, total_size); 78 | return NULL; 79 | } 80 | 81 | /* Spinlock initialization */ 82 | for (i = 0; i < p->n_entries; i++) { 83 | rte_spinlock_init(&t->lock[i]); 84 | } 85 | 86 | /* Memory initialzation */ 87 | t->entry_size = entry_size; 88 | t->n_entries = p->n_entries; 89 | t->f_hash = p->f_hash; 90 | t->seed = p->seed; 91 | 92 | return t; 93 | } 94 | 95 | int 96 | rte_table_netflow_entry_add( 97 | void *table, 98 | void *key, 99 | void *entry, 100 | int *key_found, 101 | void **entry_ptr) 102 | { 103 | struct rte_table_netflow *t = (struct rte_table_netflow *)table; 104 | union rte_table_netflow_key *k = key; 105 | struct ipv4_hdr *ip = entry; 106 | struct tcp_hdr *tcp; 107 | hashBucket_t *previous_pointer = NULL; 108 | hashBucket_t *bucket = NULL; 109 | hashBucket_t *bkt = NULL; 110 | uint32_t idx = 0; 111 | uint8_t updated = 0; 112 | uint8_t notfound = 0; 113 | struct timeval curr; 114 | 115 | /* hashing with SSE4_2 CRC32 */ 116 | idx = rte_hash_crc_4byte(k->proto, idx); 117 | idx = rte_hash_crc_4byte(k->ip_src, idx); 118 | idx = rte_hash_crc_4byte(k->ip_dst, idx); 119 | idx = rte_hash_crc_4byte(k->port_src, idx); 120 | idx = rte_hash_crc_4byte(k->port_dst, idx); 121 | idx = idx % t->n_entries; 122 | 123 | /**************************************************************** 124 | * Lock one entry (t->array[idx]'s lock = t->lock[idex] 125 | * 126 | * So netflow_export can use other entries 127 | ****************************************************************/ 128 | rte_spinlock_lock(&t->lock[idx]); 129 | 130 | bucket = t->array[idx]; 131 | previous_pointer = bucket; 132 | 133 | while (bucket != NULL) { 134 | /* Find same flow in the bucket's list */ 135 | if ((bucket->ip_src == k->ip_src) && (bucket->ip_dst == k->ip_dst) ) { 136 | /* accumulated ToS Field */ 137 | bucket->src2dstTos |= ip->type_of_service; 138 | 139 | /* accumulated TCP Flags */ 140 | if (k->proto == IPPROTO_TCP) { 141 | tcp = (struct tcp_hdr *)((unsigned char*)ip + sizeof(struct ipv4_hdr)); 142 | bucket->src2dstTcpFlags |= tcp->tcp_flags; 143 | } 144 | 145 | /* accumulated Bytes */ 146 | /* TODO: if bytesSent > 2^32, netflow v5 value is wrong 147 | * since, netflow v5 dOctet is 32bit. 148 | */ 149 | bucket->bytesSent += rte_cpu_to_be_16(ip->total_length); 150 | bucket->pktSent++; 151 | 152 | /* Time */ 153 | gettimeofday(&curr, NULL); 154 | bucket->lastSeenSent = curr; 155 | 156 | updated = 1; 157 | break; 158 | } 159 | printf("Bucket collision\n"); 160 | notfound = 1; 161 | previous_pointer = bucket; 162 | bucket = bucket->next; 163 | } 164 | 165 | if( !updated ) { 166 | /* Create New Bucket */ 167 | //printf("First Seen : %" PRIu32 "\n", idx); 168 | bkt = (hashBucket_t *)rte_zmalloc("BUCKET", sizeof(hashBucket_t), CACHE_LINE_SIZE); 169 | bkt->magic = 1; 170 | bkt->vlanId = k->vlanId; 171 | bkt->proto = k->proto; 172 | bkt->ip_src = k->ip_src; 173 | bkt->ip_dst = k->ip_dst; 174 | bkt->port_src = k->port_src; 175 | bkt->port_dst = k->port_dst; 176 | 177 | /* ToS Field */ 178 | bkt->src2dstTos = ip->type_of_service; 179 | 180 | /* TCP Flags */ 181 | if (k->proto == IPPROTO_TCP) { 182 | tcp = (struct tcp_hdr *)((unsigned char*)ip + sizeof(struct ipv4_hdr)); 183 | bkt->src2dstTcpFlags = tcp->tcp_flags; 184 | 185 | /* TODO: If TCP flags is start of Flow (Syn) 186 | * Save payload of DPI 187 | */ 188 | 189 | /* If Flags is FIN, check and of flow */ 190 | } 191 | 192 | /* Bytes (Total number of Layer 3 bytes) */ 193 | bkt->bytesSent = rte_cpu_to_be_16(ip->total_length); 194 | bkt->pktSent++; 195 | 196 | /* Time */ 197 | gettimeofday(&curr, NULL); 198 | bkt->firstSeenSent = bkt->lastSeenSent = curr; 199 | 200 | /* Update contents of bucket */ 201 | if (notfound) previous_pointer->next = bkt; 202 | else t->array[idx] = bkt; 203 | } 204 | 205 | rte_spinlock_unlock(&t->lock[idx]); 206 | /*********************************************************************** 207 | * End of entry lock 208 | * release lock 209 | **********************************************************************/ 210 | return 1; 211 | } 212 | static int 213 | rte_table_netflow_free(void *table) 214 | { 215 | struct rte_table_netflow *t = (struct rte_table_netflow *)table; 216 | 217 | /* Check input paramters */ 218 | if (t == NULL) { 219 | RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__); 220 | return -EINVAL; 221 | } 222 | 223 | /* Free previously allocated resources */ 224 | rte_free(t); 225 | return 0; 226 | } 227 | 228 | 229 | struct rte_table_ops rte_table_netflow_ops = { 230 | .f_create = rte_table_netflow_create, 231 | .f_free = rte_table_netflow_free, 232 | .f_add = rte_table_netflow_entry_add, 233 | .f_delete = NULL, 234 | .f_lookup = NULL, /* rte_table_netflow_lookup, */ 235 | }; 236 | 237 | 238 | -------------------------------------------------------------------------------- /rte_table_netflow.h: -------------------------------------------------------------------------------- 1 | #ifndef __INCLUDE_RTE_TABLE_NETFLOW_H__ 2 | #define __INCLUDE_RTE_TABLE_NETFLOW_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * @file 10 | * RTE Table Netflow 11 | * 12 | * array indexing, Lookup key is the array entry index. 13 | * 14 | ***/ 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "rte_table.h" 25 | 26 | #define MAX_ENTRY 2 * 1024 * 1024 27 | 28 | /* ***************************************** */ 29 | 30 | #define FLOW_VERSION_5 5 31 | #define V5FLOWS_PER_PAK 30 32 | 33 | struct flow_ver5_hdr { 34 | u_int16_t version; /* Current version=5*/ 35 | u_int16_t count; /* The number of records in PDU. */ 36 | u_int32_t sysUptime; /* Current time in msecs since router booted */ 37 | u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ 38 | u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ 39 | u_int32_t flow_sequence; /* Sequence number of total flows seen */ 40 | u_int8_t engine_type; /* Type of flow switching engine (RP,VIP,etc.)*/ 41 | u_int8_t engine_id; /* Slot number of the flow switching engine */ 42 | u_int16_t sampleRate; /* Packet capture sample rate */ 43 | }; 44 | 45 | struct flow_ver5_rec { 46 | u_int32_t srcaddr; /* Source IP Address */ 47 | u_int32_t dstaddr; /* Destination IP Address */ 48 | u_int32_t nexthop; /* Next hop router's IP Address */ 49 | u_int16_t input; /* Input interface index */ 50 | u_int16_t output; /* Output interface index */ 51 | u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st 52 | & last packet in this flow)*/ 53 | u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st 54 | & last packet in this flow)*/ 55 | u_int32_t first; /* SysUptime at start of flow */ 56 | u_int32_t last; /* and of last packet of the flow */ 57 | u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ 58 | u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ 59 | u_int8_t pad1; /* pad to word boundary */ 60 | u_int8_t tcp_flags; /* Cumulative OR of tcp flags */ 61 | u_int8_t proto; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ 62 | u_int8_t tos; /* IP Type-of-Service */ 63 | u_int16_t src_as; /* source peer/origin Autonomous System */ 64 | u_int16_t dst_as; /* dst peer/origin Autonomous System */ 65 | u_int8_t src_mask; /* source route's mask bits */ 66 | u_int8_t dst_mask; /* destination route's mask bits */ 67 | u_int16_t pad2; /* pad to word boundary */ 68 | }; 69 | 70 | typedef struct single_flow_ver5_rec { 71 | struct flow_ver5_hdr flowHeader; 72 | struct flow_ver5_rec flowRecord[V5FLOWS_PER_PAK+1 /* safe against buffer overflows */]; 73 | } NetFlow5Record; 74 | 75 | typedef struct rte_table_hashBucket { 76 | uint8_t magic; /**< magic code for validation */ 77 | uint8_t bucket_expired; /**< force bucket to expire */ 78 | uint8_t vlanId; 79 | uint8_t proto; 80 | 81 | uint32_t ip_src; /**< saved in network order */ 82 | uint32_t ip_dst; /**< saved in network order */ 83 | uint16_t port_src; /**< saved in network order */ 84 | uint16_t port_dst; /**< saved in network order */ 85 | 86 | uint8_t src2dstTos, dst2srcTos; 87 | uint8_t src2dstTcpFlags, dst2srcTcpFlags; 88 | uint8_t pad1, pad2; 89 | 90 | uint64_t bytesSent, pktSent; /**< saved in host order */ 91 | uint64_t bytesRcvd, pktRcvd; /**< saved in host order */ 92 | struct timeval firstSeenRcvd, lastSeenRcvd; /**< sizeof(timeval) = 16 Bytes */ 93 | struct timeval firstSeenSent, lastSeenSent; 94 | 95 | 96 | struct rte_table_hashBucket *next; 97 | } hashBucket_t; 98 | 99 | /** Netflow table key format */ 100 | union rte_table_netflow_key { 101 | struct { 102 | uint8_t pad0; 103 | uint8_t vlanId; 104 | uint8_t pad1; 105 | uint8_t proto; 106 | uint32_t ip_src; 107 | uint32_t ip_dst; 108 | uint16_t port_src; 109 | uint16_t port_dst; 110 | }; 111 | __m128i xmm; 112 | }; 113 | 114 | 115 | /** Hash function (rte_hash_crc_4bytes) */ 116 | typedef uint32_t (*rte_table_netflow_op_hash)( 117 | uint32_t key, 118 | uint32_t seed); 119 | 120 | 121 | /** Netflow table parameters */ 122 | struct rte_table_netflow_params { 123 | /** Number of array entries. Has to be a power of two. */ 124 | uint32_t n_entries; 125 | 126 | /** Byte offset within input */ 127 | uint32_t offset; 128 | 129 | /** Hash function */ 130 | rte_table_netflow_op_hash f_hash; 131 | 132 | /** Seed value for the hash function */ 133 | uint64_t seed; 134 | 135 | }; 136 | 137 | struct rte_table_netflow { 138 | /* Input parameters */ 139 | uint32_t entry_size; 140 | uint32_t n_entries; 141 | 142 | rte_table_netflow_op_hash f_hash; 143 | uint64_t seed; 144 | 145 | /* Spinlock for entry */ 146 | rte_spinlock_t lock[MAX_ENTRY]; 147 | 148 | /* Internal table */ 149 | hashBucket_t *array[0] __rte_cache_aligned; 150 | } __rte_cache_aligned; 151 | 152 | 153 | /** Netflow table operations */ 154 | extern struct rte_table_ops rte_table_netflow_ops; 155 | 156 | void *rte_table_netflow_create(void *, int, uint32_t); 157 | 158 | #ifdef __cplusplus 159 | } 160 | #endif 161 | 162 | #endif 163 | --------------------------------------------------------------------------------