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