]> git.proxmox.com Git - mirror_frr.git/blob - zebra/dpdk/zebra_dplane_dpdk.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / zebra / dpdk / zebra_dplane_dpdk.c
1 /*
2 * Zebra dataplane plugin for DPDK based hw offload
3 *
4 * Copyright (C) 2021 Nvidia
5 * Anuradha Karuppiah
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h" /* Include this explicitly */
24 #endif
25
26 #include "lib/libfrr.h"
27
28 #include "zebra/debug.h"
29 #include "zebra/interface.h"
30 #include "zebra/zebra_dplane.h"
31 #include "zebra/debug.h"
32 #include "zebra/zebra_pbr.h"
33
34 #include "zebra/dpdk/zebra_dplane_dpdk_private.h"
35
36 static const char *plugin_name = "zebra_dplane_dpdk";
37
38 static struct zd_dpdk_ctx dpdk_ctx_buf, *dpdk_ctx = &dpdk_ctx_buf;
39 #define dpdk_stat (&dpdk_ctx->stats)
40
41 static struct zd_dpdk_port *zd_dpdk_port_find_by_index(int ifindex);
42
43 DEFINE_MTYPE_STATIC(ZEBRA, DPDK_PORTS, "ZD DPDK port database");
44
45 void zd_dpdk_stat_show(struct vty *vty)
46 {
47 uint32_t tmp_cnt;
48
49 vty_out(vty, "%30s\n%30s\n", "Dataplane DPDK counters",
50 "=======================");
51
52 #define ZD_DPDK_SHOW_COUNTER(label, counter) \
53 do { \
54 tmp_cnt = \
55 atomic_load_explicit(&counter, memory_order_relaxed); \
56 vty_out(vty, "%28s: %u\n", (label), (tmp_cnt)); \
57 } while (0)
58
59 ZD_DPDK_SHOW_COUNTER("PBR rule adds", dpdk_stat->rule_adds);
60 ZD_DPDK_SHOW_COUNTER("PBR rule dels", dpdk_stat->rule_dels);
61 ZD_DPDK_SHOW_COUNTER("Ignored updates", dpdk_stat->ignored_updates);
62 }
63
64
65 static void zd_dpdk_flow_stat_show(struct vty *vty, int in_ifindex,
66 intptr_t dp_flow_ptr)
67 {
68 struct rte_flow_action_count count = {.shared = 0, .id = 0};
69 const struct rte_flow_action actions[] = {
70 {
71 .type = RTE_FLOW_ACTION_TYPE_COUNT,
72 .conf = &count,
73 },
74 {
75 .type = RTE_FLOW_ACTION_TYPE_END,
76 },
77 };
78 int rc;
79 struct zd_dpdk_port *in_dport;
80 struct rte_flow_query_count query;
81 struct rte_flow_error error;
82 uint64_t hits, bytes;
83
84 in_dport = zd_dpdk_port_find_by_index(in_ifindex);
85 if (!in_dport) {
86 vty_out(vty, "PBR dpdk flow query failed; in_port %d missing\n",
87 in_ifindex);
88 return;
89 }
90 memset(&query, 0, sizeof(query));
91 rc = rte_flow_query(in_dport->port_id, (struct rte_flow *)dp_flow_ptr,
92 actions, &query, &error);
93 if (rc) {
94 vty_out(vty,
95 "PBR dpdk flow query failed; in_ifindex %d rc %d\n",
96 in_ifindex, error.type);
97 return;
98 }
99 hits = (query.hits_set) ? query.hits : 0;
100 bytes = (query.bytes_set) ? query.bytes : 0;
101 vty_out(vty, " DPDK stats: packets %" PRIu64 " bytes %" PRIu64 "\n",
102 hits, bytes);
103 }
104
105
106 static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
107 {
108 struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
109 struct vty *vty = (struct vty *)arg;
110 struct vrf *vrf;
111 struct interface *ifp = NULL;
112 struct zebra_pbr_action *zaction = &rule->action;
113
114 zebra_pbr_show_rule_unit(rule, vty);
115 if (zaction->dp_flow_ptr) {
116 vrf = vrf_lookup_by_id(rule->vrf_id);
117 if (vrf)
118 ifp = if_lookup_by_name_vrf(rule->ifname, vrf);
119
120 if (ifp)
121 zd_dpdk_flow_stat_show(vty, ifp->ifindex,
122 zaction->dp_flow_ptr);
123 }
124 return HASHWALK_CONTINUE;
125 }
126
127
128 void zd_dpdk_pbr_flows_show(struct vty *vty)
129 {
130 hash_walk(zrouter.rules_hash, zd_dpdk_pbr_show_rules_walkcb, vty);
131 }
132
133
134 static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
135 {
136 static struct rte_flow_attr attrs = {.ingress = 1, .transfer = 1};
137 uint32_t filter_bm = dplane_ctx_rule_get_filter_bm(ctx);
138 int in_ifindex = dplane_ctx_get_ifindex(ctx);
139 int out_ifindex = dplane_ctx_rule_get_out_ifindex(ctx);
140 struct rte_flow_item_eth eth, eth_mask;
141 struct rte_flow_item_ipv4 ip, ip_mask;
142 struct rte_flow_item_udp udp, udp_mask;
143 struct rte_flow_action_count conf_count;
144 struct rte_flow_action_set_mac conf_smac, conf_dmac;
145 struct rte_flow_action_port_id conf_port;
146 struct rte_flow_item items[ZD_PBR_PATTERN_MAX];
147 struct rte_flow_action actions[ZD_PBR_ACTION_MAX];
148 int item_cnt = 0;
149 int act_cnt = 0;
150 struct in_addr tmp_mask;
151 const struct ethaddr *mac;
152 struct rte_flow *flow;
153 struct rte_flow_error error;
154 struct zd_dpdk_port *in_dport;
155 struct zd_dpdk_port *out_dport;
156 uint32_t pri = dplane_ctx_rule_get_priority(ctx);
157 int seq = dplane_ctx_rule_get_seq(ctx);
158 int unique = dplane_ctx_rule_get_unique(ctx);
159
160 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
161 zlog_debug(
162 "PBR dpdk flow create ifname %s seq %d pri %u unique %d\n",
163 dplane_ctx_rule_get_ifname(ctx), seq, pri, unique);
164 in_dport = zd_dpdk_port_find_by_index(in_ifindex);
165 if (!in_dport) {
166 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
167 zlog_debug(
168 "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n",
169 dplane_ctx_rule_get_ifname(ctx), seq, pri,
170 unique, in_ifindex);
171 return;
172 }
173
174 out_dport = zd_dpdk_port_find_by_index(out_ifindex);
175 if (!out_dport) {
176 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
177 zlog_debug(
178 "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n",
179 dplane_ctx_rule_get_ifname(ctx), seq, pri,
180 unique, out_ifindex);
181 return;
182 }
183
184 /*********************** match items **************************/
185 memset(&eth, 0, sizeof(eth));
186 memset(&eth_mask, 0, sizeof(eth_mask));
187 eth.type = eth_mask.type = htons(RTE_ETHER_TYPE_IPV4);
188 items[item_cnt].type = RTE_FLOW_ITEM_TYPE_ETH;
189 items[item_cnt].spec = ð
190 items[item_cnt].mask = &eth_mask;
191 items[item_cnt].last = NULL;
192 ++item_cnt;
193
194 memset(&ip, 0, sizeof(ip));
195 memset(&ip_mask, 0, sizeof(ip_mask));
196 if (filter_bm & PBR_FILTER_SRC_IP) {
197 const struct prefix *src_ip;
198
199 src_ip = dplane_ctx_rule_get_src_ip(ctx);
200 ip.hdr.src_addr = src_ip->u.prefix4.s_addr;
201 masklen2ip(src_ip->prefixlen, &tmp_mask);
202 ip_mask.hdr.src_addr = tmp_mask.s_addr;
203 }
204 if (filter_bm & PBR_FILTER_DST_IP) {
205 const struct prefix *dst_ip;
206
207 dst_ip = dplane_ctx_rule_get_dst_ip(ctx);
208 ip.hdr.dst_addr = dst_ip->u.prefix4.s_addr;
209 masklen2ip(dst_ip->prefixlen, &tmp_mask);
210 ip_mask.hdr.dst_addr = tmp_mask.s_addr;
211 }
212 if (filter_bm & PBR_FILTER_IP_PROTOCOL) {
213 ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx);
214 ip_mask.hdr.next_proto_id = UINT8_MAX;
215 }
216 items[item_cnt].type = RTE_FLOW_ITEM_TYPE_IPV4;
217 items[item_cnt].spec = &ip;
218 items[item_cnt].mask = &ip_mask;
219 items[item_cnt].last = NULL;
220 ++item_cnt;
221
222 if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) {
223 memset(&udp, 0, sizeof(udp));
224 memset(&udp_mask, 0, sizeof(udp_mask));
225 if (filter_bm & PBR_FILTER_SRC_PORT) {
226 udp.hdr.src_port =
227 RTE_BE16(dplane_ctx_rule_get_src_port(ctx));
228 udp_mask.hdr.src_port = UINT16_MAX;
229 }
230 if (filter_bm & PBR_FILTER_DST_PORT) {
231 udp.hdr.dst_port =
232 RTE_BE16(dplane_ctx_rule_get_dst_port(ctx));
233 udp_mask.hdr.dst_port = UINT16_MAX;
234 }
235 items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP;
236 items[item_cnt].spec = &udp;
237 items[item_cnt].mask = &udp_mask;
238 items[item_cnt].last = NULL;
239 ++item_cnt;
240 }
241
242 items[item_cnt].type = RTE_FLOW_ITEM_TYPE_END;
243
244 /*************************** actions *****************************/
245 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_COUNT;
246 memset(&conf_count, 0, sizeof(conf_count));
247 actions[act_cnt].conf = &conf_count;
248 ++act_cnt;
249
250 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_DEC_TTL;
251 ++act_cnt;
252
253 mac = dplane_ctx_rule_get_smac(ctx);
254 memcpy(conf_smac.mac_addr, mac, RTE_ETHER_ADDR_LEN);
255 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_SET_MAC_SRC;
256 actions[act_cnt].conf = &conf_smac;
257 ++act_cnt;
258
259 mac = dplane_ctx_rule_get_dmac(ctx);
260 memcpy(conf_dmac.mac_addr, mac, RTE_ETHER_ADDR_LEN);
261 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_SET_MAC_DST;
262 actions[act_cnt].conf = &conf_dmac;
263 ++act_cnt;
264
265 memset(&conf_port, 0, sizeof(conf_port));
266 conf_port.id = out_dport->port_id;
267 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_PORT_ID;
268 actions[act_cnt].conf = &conf_port;
269 ++act_cnt;
270
271 actions[act_cnt].type = RTE_FLOW_ACTION_TYPE_END;
272
273 frr_with_privs (&zserv_privs) {
274 flow = rte_flow_create(in_dport->port_id, &attrs, items,
275 actions, &error);
276 }
277
278 if (flow) {
279 dplane_ctx_rule_set_dp_flow_ptr(ctx, (intptr_t)flow);
280 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
281 zlog_debug(
282 "PBR dpdk flow 0x%" PRIxPTR
283 " created ifname %s seq %d pri %u unique %d\n",
284 (intptr_t)flow, dplane_ctx_rule_get_ifname(ctx),
285 seq, pri, unique);
286 } else {
287 zlog_warn(
288 "PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n",
289 dplane_ctx_rule_get_ifname(ctx), seq, pri, unique,
290 error.type);
291 }
292 }
293
294
295 static void zd_dpdk_rule_del(struct zebra_dplane_ctx *ctx, const char *ifname,
296 int in_ifindex, intptr_t dp_flow_ptr)
297 {
298 struct zd_dpdk_port *in_dport;
299 struct rte_flow_error error;
300 int rc;
301
302 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
303 zlog_debug(
304 "PBR dpdk flow delete ifname %s ifindex %d dp_flow 0x%" PRIxPTR
305 "\n",
306 ifname, in_ifindex, dp_flow_ptr);
307
308 if (!dp_flow_ptr) {
309 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
310 zlog_debug(
311 "PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
312 "; empty dp\n",
313 ifname, in_ifindex, dp_flow_ptr);
314 return;
315 }
316
317 dplane_ctx_rule_set_dp_flow_ptr(ctx, (intptr_t)NULL);
318 in_dport = zd_dpdk_port_find_by_index(in_ifindex);
319 if (!in_dport) {
320 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
321 zlog_debug(
322 "PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
323 " in port missing\n",
324 ifname, in_ifindex, dp_flow_ptr);
325 return;
326 }
327
328 frr_with_privs (&zserv_privs) {
329 rc = rte_flow_destroy(in_dport->port_id,
330 (struct rte_flow *)dp_flow_ptr, &error);
331 }
332
333 if (rc)
334 zlog_warn(
335 "PBR dpdk flow delete failed; ifname %s ifindex %d dp_flow 0x%" PRIxPTR
336 "\n",
337 ifname, in_ifindex, dp_flow_ptr);
338 }
339
340
341 static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx)
342 {
343 enum dplane_op_e op;
344 int in_ifindex;
345 intptr_t dp_flow_ptr;
346
347 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
348 zlog_debug("Dplane %s", dplane_op2str(dplane_ctx_get_op(ctx)));
349
350
351 op = dplane_ctx_get_op(ctx);
352 switch (op) {
353 case DPLANE_OP_RULE_ADD:
354 atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1,
355 memory_order_relaxed);
356 zd_dpdk_rule_add(ctx);
357 break;
358
359 case DPLANE_OP_RULE_UPDATE:
360 /* delete old rule and install new one */
361 atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1,
362 memory_order_relaxed);
363 in_ifindex = dplane_ctx_get_ifindex(ctx);
364 dp_flow_ptr = dplane_ctx_rule_get_old_dp_flow_ptr(ctx);
365 zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx),
366 in_ifindex, dp_flow_ptr);
367 zd_dpdk_rule_add(ctx);
368 break;
369
370 case DPLANE_OP_RULE_DELETE:
371 atomic_fetch_add_explicit(&dpdk_stat->rule_dels, 1,
372 memory_order_relaxed);
373 in_ifindex = dplane_ctx_get_ifindex(ctx);
374 dp_flow_ptr = dplane_ctx_rule_get_dp_flow_ptr(ctx);
375 zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx),
376 in_ifindex, dp_flow_ptr);
377 break;
378
379 case DPLANE_OP_NONE:
380 case DPLANE_OP_ROUTE_INSTALL:
381 case DPLANE_OP_ROUTE_UPDATE:
382 case DPLANE_OP_ROUTE_DELETE:
383 case DPLANE_OP_ROUTE_NOTIFY:
384 case DPLANE_OP_NH_INSTALL:
385 case DPLANE_OP_NH_UPDATE:
386 case DPLANE_OP_NH_DELETE:
387 case DPLANE_OP_LSP_INSTALL:
388 case DPLANE_OP_LSP_UPDATE:
389 case DPLANE_OP_LSP_DELETE:
390 case DPLANE_OP_LSP_NOTIFY:
391 case DPLANE_OP_PW_INSTALL:
392 case DPLANE_OP_PW_UNINSTALL:
393 case DPLANE_OP_SYS_ROUTE_ADD:
394 case DPLANE_OP_SYS_ROUTE_DELETE:
395 case DPLANE_OP_ADDR_INSTALL:
396 case DPLANE_OP_ADDR_UNINSTALL:
397 case DPLANE_OP_MAC_INSTALL:
398 case DPLANE_OP_MAC_DELETE:
399 case DPLANE_OP_NEIGH_INSTALL:
400 case DPLANE_OP_NEIGH_UPDATE:
401 case DPLANE_OP_NEIGH_DELETE:
402 case DPLANE_OP_VTEP_ADD:
403 case DPLANE_OP_VTEP_DELETE:
404 case DPLANE_OP_NEIGH_DISCOVER:
405 case DPLANE_OP_BR_PORT_UPDATE:
406 case DPLANE_OP_IPTABLE_ADD:
407 case DPLANE_OP_IPTABLE_DELETE:
408 case DPLANE_OP_IPSET_ADD:
409 case DPLANE_OP_IPSET_DELETE:
410 case DPLANE_OP_IPSET_ENTRY_ADD:
411 case DPLANE_OP_IPSET_ENTRY_DELETE:
412 case DPLANE_OP_NEIGH_IP_INSTALL:
413 case DPLANE_OP_NEIGH_IP_DELETE:
414 case DPLANE_OP_NEIGH_TABLE_UPDATE:
415 case DPLANE_OP_GRE_SET:
416 case DPLANE_OP_INTF_ADDR_ADD:
417 case DPLANE_OP_INTF_ADDR_DEL:
418 case DPLANE_OP_INTF_NETCONFIG:
419 case DPLANE_OP_INTF_INSTALL:
420 case DPLANE_OP_INTF_UPDATE:
421 case DPLANE_OP_INTF_DELETE:
422 break;
423 }
424 }
425
426
427 /* DPDK provider callback.
428 */
429 static void zd_dpdk_process_update(struct zebra_dplane_ctx *ctx)
430 {
431 switch (dplane_ctx_get_op(ctx)) {
432
433 case DPLANE_OP_RULE_ADD:
434 case DPLANE_OP_RULE_UPDATE:
435 case DPLANE_OP_RULE_DELETE:
436 zd_dpdk_rule_update(ctx);
437 break;
438 case DPLANE_OP_NONE:
439 case DPLANE_OP_ROUTE_INSTALL:
440 case DPLANE_OP_ROUTE_UPDATE:
441 case DPLANE_OP_ROUTE_DELETE:
442 case DPLANE_OP_ROUTE_NOTIFY:
443 case DPLANE_OP_NH_INSTALL:
444 case DPLANE_OP_NH_UPDATE:
445 case DPLANE_OP_NH_DELETE:
446 case DPLANE_OP_LSP_INSTALL:
447 case DPLANE_OP_LSP_UPDATE:
448 case DPLANE_OP_LSP_DELETE:
449 case DPLANE_OP_LSP_NOTIFY:
450 case DPLANE_OP_PW_INSTALL:
451 case DPLANE_OP_PW_UNINSTALL:
452 case DPLANE_OP_SYS_ROUTE_ADD:
453 case DPLANE_OP_SYS_ROUTE_DELETE:
454 case DPLANE_OP_ADDR_INSTALL:
455 case DPLANE_OP_ADDR_UNINSTALL:
456 case DPLANE_OP_MAC_INSTALL:
457 case DPLANE_OP_MAC_DELETE:
458 case DPLANE_OP_NEIGH_INSTALL:
459 case DPLANE_OP_NEIGH_UPDATE:
460 case DPLANE_OP_NEIGH_DELETE:
461 case DPLANE_OP_VTEP_ADD:
462 case DPLANE_OP_VTEP_DELETE:
463 case DPLANE_OP_NEIGH_DISCOVER:
464 case DPLANE_OP_BR_PORT_UPDATE:
465 case DPLANE_OP_IPTABLE_ADD:
466 case DPLANE_OP_IPTABLE_DELETE:
467 case DPLANE_OP_IPSET_ADD:
468 case DPLANE_OP_IPSET_DELETE:
469 case DPLANE_OP_IPSET_ENTRY_ADD:
470 case DPLANE_OP_IPSET_ENTRY_DELETE:
471 case DPLANE_OP_NEIGH_IP_INSTALL:
472 case DPLANE_OP_NEIGH_IP_DELETE:
473 case DPLANE_OP_NEIGH_TABLE_UPDATE:
474 case DPLANE_OP_GRE_SET:
475 case DPLANE_OP_INTF_ADDR_ADD:
476 case DPLANE_OP_INTF_ADDR_DEL:
477 case DPLANE_OP_INTF_NETCONFIG:
478 case DPLANE_OP_INTF_INSTALL:
479 case DPLANE_OP_INTF_UPDATE:
480 case DPLANE_OP_INTF_DELETE:
481 atomic_fetch_add_explicit(&dpdk_stat->ignored_updates, 1,
482 memory_order_relaxed);
483
484 break;
485 }
486 }
487
488
489 static int zd_dpdk_process(struct zebra_dplane_provider *prov)
490 {
491 struct zebra_dplane_ctx *ctx;
492 int counter, limit;
493
494 if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
495 zlog_debug("processing %s", dplane_provider_get_name(prov));
496
497 limit = dplane_provider_get_work_limit(prov);
498 for (counter = 0; counter < limit; counter++) {
499 ctx = dplane_provider_dequeue_in_ctx(prov);
500 if (!ctx)
501 break;
502
503 zd_dpdk_process_update(ctx);
504 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
505 dplane_provider_enqueue_out_ctx(prov, ctx);
506 }
507
508 return 0;
509 }
510
511 static void zd_dpdk_port_show_entry(struct zd_dpdk_port *dport, struct vty *vty,
512 int detail)
513 {
514 struct rte_eth_dev_info *dev_info;
515
516 dev_info = &dport->dev_info;
517 if (detail) {
518 vty_out(vty, "DPDK port: %u\n", dport->port_id);
519 vty_out(vty, " Device: %s\n",
520 dev_info->device ? dev_info->device->name : "-");
521 vty_out(vty, " Driver: %s\n",
522 dev_info->driver_name ? dev_info->driver_name : "-");
523 vty_out(vty, " Interface: %s (%d)\n",
524 ifindex2ifname(dev_info->if_index, VRF_DEFAULT),
525 dev_info->if_index);
526 vty_out(vty, " Switch: %s Domain: %u Port: %u\n",
527 dev_info->switch_info.name,
528 dev_info->switch_info.domain_id,
529 dev_info->switch_info.port_id);
530 vty_out(vty, "\n");
531 } else {
532 vty_out(vty, "%-4u %-16s %-16s %-16d %s,%u,%u\n",
533 dport->port_id,
534 dev_info->device ? dev_info->device->name : "-",
535 ifindex2ifname(dev_info->if_index, VRF_DEFAULT),
536 dev_info->if_index, dev_info->switch_info.name,
537 dev_info->switch_info.domain_id,
538 dev_info->switch_info.port_id);
539 }
540 }
541
542
543 static struct zd_dpdk_port *zd_dpdk_port_find_by_index(int ifindex)
544 {
545 int count;
546 struct zd_dpdk_port *dport;
547 struct rte_eth_dev_info *dev_info;
548
549 for (count = 0; count < RTE_MAX_ETHPORTS; ++count) {
550 dport = &dpdk_ctx->dpdk_ports[count];
551 if (!(dport->flags & ZD_DPDK_PORT_FLAG_INITED))
552 continue;
553 dev_info = &dport->dev_info;
554 if (dev_info->if_index == (uint32_t)ifindex)
555 return dport;
556 }
557
558 return NULL;
559 }
560
561
562 void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail)
563 {
564 int count;
565 struct zd_dpdk_port *dport;
566
567 /* XXX - support for json is yet to be added */
568 if (uj)
569 return;
570
571 if (!detail) {
572 vty_out(vty, "%-4s %-16s %-16s %-16s %s\n", "Port", "Device",
573 "IfName", "IfIndex", "sw,domain,port");
574 }
575
576 for (count = 0; count < RTE_MAX_ETHPORTS; ++count) {
577 dport = &dpdk_ctx->dpdk_ports[count];
578 if (dport->flags & ZD_DPDK_PORT_FLAG_INITED)
579 zd_dpdk_port_show_entry(dport, vty, detail);
580 }
581 }
582
583
584 static void zd_dpdk_port_init(void)
585 {
586 struct zd_dpdk_port *dport;
587 uint16_t port_id;
588 struct rte_eth_dev_info *dev_info;
589 int count;
590 int rc;
591 struct rte_flow_error error;
592
593 /* allocate a list of ports */
594 dpdk_ctx->dpdk_ports =
595 XCALLOC(MTYPE_DPDK_PORTS,
596 sizeof(struct zd_dpdk_port) * RTE_MAX_ETHPORTS);
597
598 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
599 zlog_debug("dpdk port init");
600 count = 0;
601 RTE_ETH_FOREACH_DEV(port_id)
602 {
603 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
604 zlog_debug("dpdk port init %d", port_id);
605 dport = &dpdk_ctx->dpdk_ports[count];
606 count++;
607 dport->port_id = port_id;
608 dport->flags |= ZD_DPDK_PORT_FLAG_PROBED;
609 dev_info = &dport->dev_info;
610 if (rte_eth_dev_info_get(port_id, dev_info) < 0) {
611 zlog_warn("failed to get dev info for %u, %s", port_id,
612 rte_strerror(rte_errno));
613 continue;
614 }
615 dport->flags |= ZD_DPDK_PORT_FLAG_INITED;
616 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
617 zlog_debug(
618 "port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u",
619 port_id,
620 dev_info->device ? dev_info->device->name : "-",
621 dev_info->if_index, dev_info->switch_info.name,
622 dev_info->switch_info.domain_id,
623 dev_info->switch_info.port_id);
624 if (rte_flow_isolate(port_id, 1, &error)) {
625 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
626 zlog_debug(
627 "Flow isolate on port %u failed %d\n",
628 port_id, error.type);
629 } else {
630 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
631 zlog_debug("Flow isolate on port %u\n",
632 port_id);
633 }
634 rc = rte_eth_dev_start(port_id);
635 if (rc) {
636 zlog_warn("DPDK port %d start error: %s", port_id,
637 rte_strerror(-rc));
638 continue;
639 }
640 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
641 zlog_debug("DPDK port %d started in promiscuous mode ",
642 port_id);
643 }
644
645 if (!count) {
646 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
647 zlog_debug("no probed ethernet devices");
648 }
649 }
650
651
652 static int zd_dpdk_init(void)
653 {
654 int rc;
655 static const char *argv[] = {(char *)"/usr/lib/frr/zebra",
656 (char *)"--"};
657
658 zd_dpdk_vty_init();
659
660 frr_with_privs (&zserv_privs) {
661 rc = rte_eal_init(ARRAY_SIZE(argv), argv);
662 }
663 if (rc < 0) {
664 zlog_warn("EAL init failed %s", rte_strerror(rte_errno));
665 return -1;
666 }
667
668 frr_with_privs (&zserv_privs) {
669 zd_dpdk_port_init();
670 }
671 return 0;
672 }
673
674
675 static int zd_dpdk_start(struct zebra_dplane_provider *prov)
676 {
677 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
678 zlog_debug("%s start", dplane_provider_get_name(prov));
679
680 return zd_dpdk_init();
681 }
682
683
684 static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early)
685 {
686 int rc;
687
688 if (early) {
689 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
690 zlog_debug("%s early finish",
691 dplane_provider_get_name(prov));
692
693 return 0;
694 }
695
696 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
697 zlog_debug("%s finish", dplane_provider_get_name(prov));
698
699
700 frr_with_privs (&zserv_privs) {
701 rc = rte_eal_cleanup();
702 }
703 if (rc < 0)
704 zlog_warn("EAL cleanup failed %s", rte_strerror(rte_errno));
705
706 return 0;
707 }
708
709
710 static int zd_dpdk_plugin_init(struct thread_master *tm)
711 {
712 int ret;
713
714 ret = dplane_provider_register(
715 plugin_name, DPLANE_PRIO_KERNEL, DPLANE_PROV_FLAGS_DEFAULT,
716 zd_dpdk_start, zd_dpdk_process, zd_dpdk_finish, dpdk_ctx, NULL);
717
718 if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
719 zlog_debug("%s register status %d", plugin_name, ret);
720
721 return 0;
722 }
723
724
725 static int zd_dpdk_module_init(void)
726 {
727 hook_register(frr_late_init, zd_dpdk_plugin_init);
728 return 0;
729 }
730
731 FRR_MODULE_SETUP(.name = "dplane_dpdk", .version = "0.0.1",
732 .description = "Data plane plugin using dpdk for hw offload",
733 .init = zd_dpdk_module_init);