mbuf: remove rte_ctrlmbuf
[dpdk.git] / examples / ip_pipeline / pipeline_routing.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
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  *     * 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.
20  *
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.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37
38 #include <rte_malloc.h>
39 #include <rte_log.h>
40 #include <rte_ethdev.h>
41 #include <rte_ether.h>
42 #include <rte_ip.h>
43 #include <rte_byteorder.h>
44
45 #include <rte_port_ring.h>
46 #include <rte_table_lpm.h>
47 #include <rte_table_hash.h>
48 #include <rte_pipeline.h>
49
50 #include "main.h"
51
52 #include <unistd.h>
53
54 struct app_routing_table_entry {
55         struct rte_pipeline_table_entry head;
56         uint32_t nh_ip;
57         uint32_t nh_iface;
58 };
59
60 struct app_arp_table_entry {
61         struct rte_pipeline_table_entry head;
62         struct ether_addr nh_arp;
63 };
64
65 static inline void
66 app_routing_table_write_metadata(
67         struct rte_mbuf *pkt,
68         struct app_routing_table_entry *entry)
69 {
70         struct app_pkt_metadata *c =
71                 (struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
72
73         c->arp_key.nh_ip = entry->nh_ip;
74         c->arp_key.nh_iface = entry->nh_iface;
75 }
76
77 static int
78 app_routing_table_ah(
79         struct rte_mbuf **pkts,
80         uint64_t *pkts_mask,
81         struct rte_pipeline_table_entry **entries,
82         __attribute__((unused)) void *arg)
83 {
84         uint64_t pkts_in_mask = *pkts_mask;
85
86         if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
87                 uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
88                 uint32_t i;
89
90                 for (i = 0; i < n_pkts; i++) {
91                         struct rte_mbuf *m = pkts[i];
92                         struct app_routing_table_entry *a =
93                                 (struct app_routing_table_entry *) entries[i];
94
95                         app_routing_table_write_metadata(m, a);
96                 }
97         } else
98                 for ( ; pkts_in_mask; ) {
99                         struct rte_mbuf *m;
100                         struct app_routing_table_entry *a;
101                         uint64_t pkt_mask;
102                         uint32_t packet_index;
103
104                         packet_index = __builtin_ctzll(pkts_in_mask);
105                         pkt_mask = 1LLU << packet_index;
106                         pkts_in_mask &= ~pkt_mask;
107
108                         m = pkts[packet_index];
109                         a = (struct app_routing_table_entry *)
110                                 entries[packet_index];
111                         app_routing_table_write_metadata(m, a);
112                 }
113
114         return 0;
115 }
116
117 static inline void
118 app_arp_table_write_metadata(
119         struct rte_mbuf *pkt,
120         struct app_arp_table_entry *entry)
121 {
122         struct app_pkt_metadata *c =
123                 (struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
124         ether_addr_copy(&entry->nh_arp, &c->nh_arp);
125 }
126
127 static int
128 app_arp_table_ah(
129         struct rte_mbuf **pkts,
130         uint64_t *pkts_mask,
131         struct rte_pipeline_table_entry **entries,
132         __attribute__((unused)) void *arg)
133 {
134         uint64_t pkts_in_mask = *pkts_mask;
135
136         if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
137                 uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
138                 uint32_t i;
139
140                 for (i = 0; i < n_pkts; i++) {
141                         struct rte_mbuf *m = pkts[i];
142                         struct app_arp_table_entry *a =
143                                 (struct app_arp_table_entry *) entries[i];
144
145                         app_arp_table_write_metadata(m, a);
146                 }
147         } else {
148                 for ( ; pkts_in_mask; ) {
149                         struct rte_mbuf *m;
150                         struct app_arp_table_entry *a;
151                         uint64_t pkt_mask;
152                         uint32_t packet_index;
153
154                         packet_index = __builtin_ctzll(pkts_in_mask);
155                         pkt_mask = 1LLU << packet_index;
156                         pkts_in_mask &= ~pkt_mask;
157
158                         m = pkts[packet_index];
159                         a = (struct app_arp_table_entry *)
160                                 entries[packet_index];
161                         app_arp_table_write_metadata(m, a);
162                 }
163         }
164
165         return 0;
166 }
167
168 static uint64_t app_arp_table_hash(
169         void *key,
170         __attribute__((unused)) uint32_t key_size,
171         __attribute__((unused)) uint64_t seed)
172 {
173         uint32_t *k = (uint32_t *) key;
174
175         return k[1];
176 }
177
178 struct app_core_routing_message_handle_params {
179         struct rte_ring *ring_req;
180         struct rte_ring *ring_resp;
181         struct rte_pipeline *p;
182         uint32_t *port_out_id;
183         uint32_t routing_table_id;
184         uint32_t arp_table_id;
185 };
186
187 static void
188 app_message_handle(struct app_core_routing_message_handle_params *params);
189
190 void
191 app_main_loop_pipeline_routing(void) {
192         struct rte_pipeline_params pipeline_params = {
193                 .name = "pipeline",
194                 .socket_id = rte_socket_id(),
195         };
196
197         struct rte_pipeline *p;
198         uint32_t port_in_id[APP_MAX_PORTS];
199         uint32_t port_out_id[APP_MAX_PORTS];
200         uint32_t routing_table_id, arp_table_id;
201         uint32_t i;
202
203         uint32_t core_id = rte_lcore_id();
204         struct app_core_params *core_params = app_get_core_params(core_id);
205         struct app_core_routing_message_handle_params mh_params;
206
207         if ((core_params == NULL) || (core_params->core_type != APP_CORE_RT))
208                 rte_panic("Core %u misconfiguration\n", core_id);
209
210         RTE_LOG(INFO, USER1, "Core %u is doing routing\n", core_id);
211
212         /* Pipeline configuration */
213         p = rte_pipeline_create(&pipeline_params);
214         if (p == NULL)
215                 rte_panic("Unable to configure the pipeline\n");
216
217         /* Input port configuration */
218         for (i = 0; i < app.n_ports; i++) {
219                 struct rte_port_ring_reader_params port_ring_params = {
220                         .ring = app.rings[core_params->swq_in[i]],
221                 };
222
223                 struct rte_pipeline_port_in_params port_params = {
224                         .ops = &rte_port_ring_reader_ops,
225                         .arg_create = (void *) &port_ring_params,
226                         .f_action = NULL,
227                         .arg_ah = NULL,
228                         .burst_size = app.bsz_swq_rd,
229                 };
230
231                 if (rte_pipeline_port_in_create(p, &port_params,
232                         &port_in_id[i]))
233                         rte_panic("Unable to configure input port for "
234                                 "ring %d\n", i);
235         }
236
237         /* Output port configuration */
238         for (i = 0; i < app.n_ports; i++) {
239                 struct rte_port_ring_writer_params port_ring_params = {
240                         .ring = app.rings[core_params->swq_out[i]],
241                         .tx_burst_sz = app.bsz_swq_wr,
242                 };
243
244                 struct rte_pipeline_port_out_params port_params = {
245                         .ops = &rte_port_ring_writer_ops,
246                         .arg_create = (void *) &port_ring_params,
247                         .f_action = NULL,
248                         .f_action_bulk = NULL,
249                         .arg_ah = NULL,
250                 };
251
252                 if (rte_pipeline_port_out_create(p, &port_params,
253                         &port_out_id[i]))
254                         rte_panic("Unable to configure output port for "
255                                 "ring %d\n", i);
256         }
257
258         /* Routing table configuration */
259         {
260                 struct rte_table_lpm_params table_lpm_params = {
261                         .n_rules = app.max_routing_rules,
262                         .entry_unique_size =
263                                 sizeof(struct app_routing_table_entry),
264                         .offset = __builtin_offsetof(struct app_pkt_metadata,
265                                 flow_key.ip_dst),
266                 };
267
268                 struct rte_pipeline_table_params table_params = {
269                         .ops = &rte_table_lpm_ops,
270                         .arg_create = &table_lpm_params,
271                         .f_action_hit = app_routing_table_ah,
272                         .f_action_miss = NULL,
273                         .arg_ah = NULL,
274                         .action_data_size =
275                                 sizeof(struct app_routing_table_entry) -
276                                 sizeof(struct rte_pipeline_table_entry),
277                 };
278
279                 if (rte_pipeline_table_create(p, &table_params,
280                         &routing_table_id))
281                         rte_panic("Unable to configure the LPM table\n");
282         }
283
284         /* ARP table configuration */
285         {
286                 struct rte_table_hash_key8_lru_params table_arp_params = {
287                         .n_entries = app.max_arp_rules,
288                         .f_hash = app_arp_table_hash,
289                         .seed = 0,
290                         .signature_offset = 0, /* Unused */
291                         .key_offset = __builtin_offsetof(
292                                 struct app_pkt_metadata, arp_key),
293                 };
294
295                 struct rte_pipeline_table_params table_params = {
296                         .ops = &rte_table_hash_key8_lru_dosig_ops,
297                         .arg_create = &table_arp_params,
298                         .f_action_hit = app_arp_table_ah,
299                         .f_action_miss = NULL,
300                         .arg_ah = NULL,
301                         .action_data_size = sizeof(struct app_arp_table_entry) -
302                                 sizeof(struct rte_pipeline_table_entry),
303                 };
304
305                 if (rte_pipeline_table_create(p, &table_params, &arp_table_id))
306                         rte_panic("Unable to configure the ARP table\n");
307         }
308
309         /* Interconnecting ports and tables */
310         for (i = 0; i < app.n_ports; i++) {
311                 if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
312                         routing_table_id))
313                         rte_panic("Unable to connect input port %u to "
314                                 "table %u\n", port_in_id[i],  routing_table_id);
315         }
316
317         /* Enable input ports */
318         for (i = 0; i < app.n_ports; i++)
319                 if (rte_pipeline_port_in_enable(p, port_in_id[i]))
320                         rte_panic("Unable to enable input port %u\n",
321                                 port_in_id[i]);
322
323         /* Check pipeline consistency */
324         if (rte_pipeline_check(p) < 0)
325                 rte_panic("Pipeline consistency check failed\n");
326
327         /* Message handling */
328         mh_params.ring_req =
329                 app_get_ring_req(app_get_first_core_id(APP_CORE_RT));
330         mh_params.ring_resp =
331                 app_get_ring_resp(app_get_first_core_id(APP_CORE_RT));
332         mh_params.p = p;
333         mh_params.port_out_id = port_out_id;
334         mh_params.routing_table_id = routing_table_id;
335         mh_params.arp_table_id = arp_table_id;
336
337         /* Run-time */
338         for (i = 0; ; i++) {
339                 rte_pipeline_run(p);
340
341                 if ((i & APP_FLUSH) == 0) {
342                         rte_pipeline_flush(p);
343                         app_message_handle(&mh_params);
344                 }
345         }
346 }
347
348 void
349 app_message_handle(struct app_core_routing_message_handle_params *params)
350 {
351         struct rte_ring *ring_req = params->ring_req;
352         struct rte_ring *ring_resp;
353         void *msg;
354         struct app_msg_req *req;
355         struct app_msg_resp *resp;
356         struct rte_pipeline *p;
357         uint32_t *port_out_id;
358         uint32_t routing_table_id, arp_table_id;
359         int result;
360
361         /* Read request message */
362         result = rte_ring_sc_dequeue(ring_req, &msg);
363         if (result != 0)
364                 return;
365
366         ring_resp = params->ring_resp;
367         p = params->p;
368         port_out_id = params->port_out_id;
369         routing_table_id = params->routing_table_id;
370         arp_table_id = params->arp_table_id;
371
372         /* Handle request */
373         req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
374         switch (req->type) {
375         case APP_MSG_REQ_PING:
376         {
377                 result = 0;
378                 break;
379         }
380
381         case APP_MSG_REQ_RT_ADD:
382         {
383                 struct app_routing_table_entry entry = {
384                         .head = {
385                                 .action = RTE_PIPELINE_ACTION_TABLE,
386                                 {.table_id = arp_table_id},
387                         },
388                         .nh_ip = req->routing_add.nh_ip,
389                         .nh_iface = port_out_id[req->routing_add.port],
390                 };
391
392                 struct rte_table_lpm_key key = {
393                         .ip = req->routing_add.ip,
394                         .depth = req->routing_add.depth,
395                 };
396
397                 struct rte_pipeline_table_entry *entry_ptr;
398
399                 int key_found;
400
401                 result = rte_pipeline_table_entry_add(p, routing_table_id, &key,
402                         (struct rte_pipeline_table_entry *) &entry, &key_found,
403                         &entry_ptr);
404                 break;
405         }
406
407         case APP_MSG_REQ_RT_DEL:
408         {
409                 struct rte_table_lpm_key key = {
410                         .ip = req->routing_del.ip,
411                         .depth = req->routing_del.depth,
412                 };
413
414                 int key_found;
415
416                 result = rte_pipeline_table_entry_delete(p, routing_table_id,
417                         &key, &key_found, NULL);
418                 break;
419         }
420
421         case APP_MSG_REQ_ARP_ADD:
422         {
423
424                 struct app_arp_table_entry entry = {
425                         .head = {
426                                 .action = RTE_PIPELINE_ACTION_PORT,
427                                 {.port_id =
428                                         port_out_id[req->arp_add.out_iface]},
429                         },
430                         .nh_arp = req->arp_add.nh_arp,
431                 };
432
433                 struct app_arp_key arp_key = {
434                         .nh_ip = req->arp_add.nh_ip,
435                         .nh_iface = port_out_id[req->arp_add.out_iface],
436                 };
437
438                 struct rte_pipeline_table_entry *entry_ptr;
439
440                 int key_found;
441
442                 result = rte_pipeline_table_entry_add(p, arp_table_id, &arp_key,
443                         (struct rte_pipeline_table_entry *) &entry, &key_found,
444                         &entry_ptr);
445                 break;
446         }
447
448         case APP_MSG_REQ_ARP_DEL:
449         {
450                 struct app_arp_key arp_key = {
451                         .nh_ip = req->arp_del.nh_ip,
452                         .nh_iface = port_out_id[req->arp_del.out_iface],
453                 };
454
455                 int key_found;
456
457                 result = rte_pipeline_table_entry_delete(p, arp_table_id,
458                         &arp_key, &key_found, NULL);
459                 break;
460         }
461
462         default:
463                 rte_panic("RT Unrecognized message type (%u)\n", req->type);
464         }
465
466         /* Fill in response message */
467         resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
468         resp->result = result;
469
470         /* Send response */
471         do {
472                 result = rte_ring_sp_enqueue(ring_resp, msg);
473         } while (result == -ENOBUFS);
474 }