4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <rte_common.h>
39 #include <rte_malloc.h>
40 #include <rte_mempool.h>
41 #include <rte_ethdev.h>
42 #include <rte_cycles.h>
44 #include <rte_meter.h>
47 * Traffic metering configuration
50 #define APP_MODE_FWD 0
51 #define APP_MODE_SRTCM_COLOR_BLIND 1
52 #define APP_MODE_SRTCM_COLOR_AWARE 2
53 #define APP_MODE_TRTCM_COLOR_BLIND 3
54 #define APP_MODE_TRTCM_COLOR_AWARE 4
56 #define APP_MODE APP_MODE_SRTCM_COLOR_BLIND
62 #define APP_PKT_FLOW_POS 33
63 #define APP_PKT_COLOR_POS 5
66 #if APP_PKT_FLOW_POS > 64 || APP_PKT_COLOR_POS > 64
67 #error Byte offset needs to be less than 64
71 * Buffer pool configuration
75 #define MEMPOOL_CACHE_SIZE 256
77 static struct rte_mempool
*pool
= NULL
;
83 static struct rte_eth_conf port_conf
= {
85 .mq_mode
= ETH_MQ_RX_RSS
,
86 .max_rx_pkt_len
= ETHER_MAX_LEN
,
101 .mq_mode
= ETH_DCB_NONE
,
105 #define NIC_RX_QUEUE_DESC 128
106 #define NIC_TX_QUEUE_DESC 512
108 #define NIC_RX_QUEUE 0
109 #define NIC_TX_QUEUE 0
115 #define PKT_RX_BURST_MAX 32
116 #define PKT_TX_BURST_MAX 32
117 #define TIME_TX_DRAIN 200000ULL
119 static uint8_t port_rx
;
120 static uint8_t port_tx
;
121 static struct rte_mbuf
*pkts_rx
[PKT_RX_BURST_MAX
];
122 struct rte_eth_dev_tx_buffer
*tx_buffer
;
124 struct rte_meter_srtcm_params app_srtcm_params
[] = {
125 {.cir
= 1000000 * 46, .cbs
= 2048, .ebs
= 2048},
128 struct rte_meter_trtcm_params app_trtcm_params
[] = {
129 {.cir
= 1000000 * 46, .pir
= 1500000 * 46, .cbs
= 2048, .pbs
= 2048},
132 #define APP_FLOWS_MAX 256
134 FLOW_METER app_flows
[APP_FLOWS_MAX
];
137 app_configure_flow_table(void)
142 for (i
= 0, j
= 0; i
< APP_FLOWS_MAX
;
143 i
++, j
= (j
+ 1) % RTE_DIM(PARAMS
)) {
144 ret
= FUNC_CONFIG(&app_flows
[i
], &PARAMS
[j
]);
153 app_set_pkt_color(uint8_t *pkt_data
, enum policer_action color
)
155 pkt_data
[APP_PKT_COLOR_POS
] = (uint8_t)color
;
159 app_pkt_handle(struct rte_mbuf
*pkt
, uint64_t time
)
161 uint8_t input_color
, output_color
;
162 uint8_t *pkt_data
= rte_pktmbuf_mtod(pkt
, uint8_t *);
163 uint32_t pkt_len
= rte_pktmbuf_pkt_len(pkt
) - sizeof(struct ether_hdr
);
164 uint8_t flow_id
= (uint8_t)(pkt_data
[APP_PKT_FLOW_POS
] & (APP_FLOWS_MAX
- 1));
165 input_color
= pkt_data
[APP_PKT_COLOR_POS
];
166 enum policer_action action
;
168 /* color input is not used for blind modes */
169 output_color
= (uint8_t) FUNC_METER(&app_flows
[flow_id
], time
, pkt_len
,
170 (enum rte_meter_color
) input_color
);
172 /* Apply policing and set the output color */
173 action
= policer_table
[input_color
][output_color
];
174 app_set_pkt_color(pkt_data
, action
);
180 static __attribute__((noreturn
)) int
181 main_loop(__attribute__((unused
)) void *dummy
)
183 uint64_t current_time
, last_time
= rte_rdtsc();
184 uint32_t lcore_id
= rte_lcore_id();
186 printf("Core %u: port RX = %d, port TX = %d\n", lcore_id
, port_rx
, port_tx
);
192 /* Mechanism to avoid stale packets in the output buffer */
193 current_time
= rte_rdtsc();
194 time_diff
= current_time
- last_time
;
195 if (unlikely(time_diff
> TIME_TX_DRAIN
)) {
196 /* Flush tx buffer */
197 rte_eth_tx_buffer_flush(port_tx
, NIC_TX_QUEUE
, tx_buffer
);
198 last_time
= current_time
;
201 /* Read packet burst from NIC RX */
202 nb_rx
= rte_eth_rx_burst(port_rx
, NIC_RX_QUEUE
, pkts_rx
, PKT_RX_BURST_MAX
);
205 for (i
= 0; i
< nb_rx
; i
++) {
206 struct rte_mbuf
*pkt
= pkts_rx
[i
];
208 /* Handle current packet */
209 if (app_pkt_handle(pkt
, current_time
) == DROP
)
210 rte_pktmbuf_free(pkt
);
212 rte_eth_tx_buffer(port_tx
, NIC_TX_QUEUE
, tx_buffer
, pkt
);
218 print_usage(const char *prgname
)
220 printf ("%s [EAL options] -- -p PORTMASK\n"
221 " -p PORTMASK: hexadecimal bitmask of ports to configure\n",
226 parse_portmask(const char *portmask
)
231 /* parse hexadecimal string */
232 pm
= strtoul(portmask
, &end
, 16);
233 if ((portmask
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
242 /* Parse the argument given in the command line of the application */
244 parse_args(int argc
, char **argv
)
249 char *prgname
= argv
[0];
250 static struct option lgopts
[] = {
253 uint64_t port_mask
, i
, mask
;
257 while ((opt
= getopt_long(argc
, argvopt
, "p:", lgopts
, &option_index
)) != EOF
) {
260 port_mask
= parse_portmask(optarg
);
261 if (port_mask
== 0) {
262 printf("invalid port mask (null port mask)\n");
263 print_usage(prgname
);
267 for (i
= 0, mask
= 1; i
< 64; i
++, mask
<<= 1){
268 if (mask
& port_mask
){
275 for (i
= 0, mask
= 1; i
< 64; i
++, mask
<<= 1){
276 if (mask
& port_mask
){
283 if (port_mask
!= 0) {
284 printf("invalid port mask (more than 2 ports)\n");
285 print_usage(prgname
);
291 print_usage(prgname
);
297 print_usage(prgname
);
301 argv
[optind
-1] = prgname
;
303 optind
= 0; /* reset getopt lib */
308 main(int argc
, char **argv
)
314 ret
= rte_eal_init(argc
, argv
);
316 rte_exit(EXIT_FAILURE
, "Invalid EAL parameters\n");
319 if (rte_lcore_count() != 1) {
320 rte_exit(EXIT_FAILURE
, "This application does not accept more than one core. "
321 "Please adjust the \"-c COREMASK\" parameter accordingly.\n");
324 /* Application non-EAL arguments parse */
325 ret
= parse_args(argc
, argv
);
327 rte_exit(EXIT_FAILURE
, "Invalid input arguments\n");
329 /* Buffer pool init */
330 pool
= rte_pktmbuf_pool_create("pool", NB_MBUF
, MEMPOOL_CACHE_SIZE
,
331 0, RTE_MBUF_DEFAULT_BUF_SIZE
, rte_socket_id());
333 rte_exit(EXIT_FAILURE
, "Buffer pool creation error\n");
336 ret
= rte_eth_dev_configure(port_rx
, 1, 1, &port_conf
);
338 rte_exit(EXIT_FAILURE
, "Port %d configuration error (%d)\n", port_rx
, ret
);
340 ret
= rte_eth_rx_queue_setup(port_rx
, NIC_RX_QUEUE
, NIC_RX_QUEUE_DESC
,
341 rte_eth_dev_socket_id(port_rx
),
344 rte_exit(EXIT_FAILURE
, "Port %d RX queue setup error (%d)\n", port_rx
, ret
);
346 ret
= rte_eth_tx_queue_setup(port_rx
, NIC_TX_QUEUE
, NIC_TX_QUEUE_DESC
,
347 rte_eth_dev_socket_id(port_rx
),
350 rte_exit(EXIT_FAILURE
, "Port %d TX queue setup error (%d)\n", port_rx
, ret
);
352 ret
= rte_eth_dev_configure(port_tx
, 1, 1, &port_conf
);
354 rte_exit(EXIT_FAILURE
, "Port %d configuration error (%d)\n", port_tx
, ret
);
356 ret
= rte_eth_rx_queue_setup(port_tx
, NIC_RX_QUEUE
, NIC_RX_QUEUE_DESC
,
357 rte_eth_dev_socket_id(port_tx
),
360 rte_exit(EXIT_FAILURE
, "Port %d RX queue setup error (%d)\n", port_tx
, ret
);
362 ret
= rte_eth_tx_queue_setup(port_tx
, NIC_TX_QUEUE
, NIC_TX_QUEUE_DESC
,
363 rte_eth_dev_socket_id(port_tx
),
366 rte_exit(EXIT_FAILURE
, "Port %d TX queue setup error (%d)\n", port_tx
, ret
);
368 tx_buffer
= rte_zmalloc_socket("tx_buffer",
369 RTE_ETH_TX_BUFFER_SIZE(PKT_TX_BURST_MAX
), 0,
370 rte_eth_dev_socket_id(port_tx
));
371 if (tx_buffer
== NULL
)
372 rte_exit(EXIT_FAILURE
, "Port %d TX buffer allocation error\n",
375 rte_eth_tx_buffer_init(tx_buffer
, PKT_TX_BURST_MAX
);
377 ret
= rte_eth_dev_start(port_rx
);
379 rte_exit(EXIT_FAILURE
, "Port %d start error (%d)\n", port_rx
, ret
);
381 ret
= rte_eth_dev_start(port_tx
);
383 rte_exit(EXIT_FAILURE
, "Port %d start error (%d)\n", port_tx
, ret
);
385 rte_eth_promiscuous_enable(port_rx
);
387 rte_eth_promiscuous_enable(port_tx
);
389 /* App configuration */
390 ret
= app_configure_flow_table();
392 rte_exit(EXIT_FAILURE
, "Invalid configure flow table\n");
394 /* Launch per-lcore init on every lcore */
395 rte_eal_mp_remote_launch(main_loop
, NULL
, CALL_MASTER
);
396 RTE_LCORE_FOREACH_SLAVE(lcore_id
) {
397 if (rte_eal_wait_lcore(lcore_id
) < 0)