Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2017 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : :
7 : : #include <rte_mbuf.h>
8 : : #include <rte_malloc.h>
9 : : #include <ethdev_driver.h>
10 : : #include <rte_tcp.h>
11 : : #include <bus_vdev_driver.h>
12 : : #include <rte_kvargs.h>
13 : :
14 : : #include "rte_eth_bond.h"
15 : : #include "eth_bond_private.h"
16 : : #include "eth_bond_8023ad_private.h"
17 : :
18 : : int
19 : 0 : check_for_bonding_ethdev(const struct rte_eth_dev *eth_dev)
20 : : {
21 : : /* Check valid pointer */
22 [ # # ]: 0 : if (eth_dev == NULL ||
23 [ # # ]: 0 : eth_dev->device == NULL ||
24 [ # # ]: 0 : eth_dev->device->driver == NULL ||
25 [ # # ]: 0 : eth_dev->device->driver->name == NULL)
26 : : return -1;
27 : :
28 : : /* return 0 if driver name matches */
29 : 0 : return eth_dev->device->driver->name != pmd_bond_drv.driver.name;
30 : : }
31 : :
32 : : int
33 : 0 : valid_bonding_port_id(uint16_t port_id)
34 : : {
35 [ # # ]: 0 : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -1);
36 : 0 : return check_for_bonding_ethdev(&rte_eth_devices[port_id]);
37 : : }
38 : :
39 : : int
40 : 0 : check_for_main_bonding_ethdev(const struct rte_eth_dev *eth_dev)
41 : : {
42 : : int i;
43 : : struct bond_dev_private *internals;
44 : :
45 [ # # ]: 0 : if (check_for_bonding_ethdev(eth_dev) != 0)
46 : : return 0;
47 : :
48 : 0 : internals = eth_dev->data->dev_private;
49 : :
50 : : /* Check if any of member devices is a bonding device */
51 [ # # ]: 0 : for (i = 0; i < internals->member_count; i++)
52 [ # # ]: 0 : if (valid_bonding_port_id(internals->members[i].port_id) == 0)
53 : : return 1;
54 : :
55 : : return 0;
56 : : }
57 : :
58 : : int
59 : 0 : valid_member_port_id(struct bond_dev_private *internals, uint16_t member_port_id)
60 : : {
61 [ # # ]: 0 : RTE_ETH_VALID_PORTID_OR_ERR_RET(member_port_id, -1);
62 : :
63 : : /* Verify that member_port_id refers to a non bonding port */
64 [ # # ]: 0 : if (check_for_bonding_ethdev(&rte_eth_devices[member_port_id]) == 0 &&
65 [ # # ]: 0 : internals->mode == BONDING_MODE_8023AD) {
66 : 0 : RTE_BOND_LOG(ERR, "Cannot add member to bonding device in 802.3ad"
67 : : " mode as member is also a bonding device, only "
68 : : "physical devices can be support in this mode.");
69 : 0 : return -1;
70 : : }
71 : :
72 [ # # ]: 0 : if (internals->port_id == member_port_id) {
73 : 0 : RTE_BOND_LOG(ERR,
74 : : "Cannot add the bonding device itself as its member.");
75 : 0 : return -1;
76 : : }
77 : :
78 : : return 0;
79 : : }
80 : :
81 : : void
82 : 0 : activate_member(struct rte_eth_dev *eth_dev, uint16_t port_id)
83 : : {
84 : 0 : struct bond_dev_private *internals = eth_dev->data->dev_private;
85 : 0 : uint16_t active_count = internals->active_member_count;
86 : :
87 [ # # ]: 0 : if (internals->mode == BONDING_MODE_8023AD)
88 : 0 : bond_mode_8023ad_activate_member(eth_dev, port_id);
89 : :
90 : 0 : if (internals->mode == BONDING_MODE_TLB
91 [ # # ]: 0 : || internals->mode == BONDING_MODE_ALB) {
92 : :
93 : 0 : internals->tlb_members_order[active_count] = port_id;
94 : : }
95 : :
96 : : RTE_ASSERT(internals->active_member_count <
97 : : (RTE_DIM(internals->active_members) - 1));
98 : :
99 : 0 : internals->active_members[internals->active_member_count] = port_id;
100 : 0 : internals->active_member_count++;
101 : :
102 [ # # ]: 0 : if (internals->mode == BONDING_MODE_TLB)
103 : 0 : bond_tlb_activate_member(internals);
104 [ # # ]: 0 : if (internals->mode == BONDING_MODE_ALB)
105 : 0 : bond_mode_alb_client_list_upd(eth_dev);
106 : 0 : }
107 : :
108 : : void
109 : 0 : deactivate_member(struct rte_eth_dev *eth_dev, uint16_t port_id)
110 : : {
111 : : uint16_t member_pos;
112 : 0 : struct bond_dev_private *internals = eth_dev->data->dev_private;
113 : 0 : uint16_t active_count = internals->active_member_count;
114 : :
115 [ # # ]: 0 : if (internals->mode == BONDING_MODE_8023AD) {
116 : 0 : bond_mode_8023ad_stop(eth_dev);
117 : 0 : bond_mode_8023ad_deactivate_member(eth_dev, port_id);
118 : 0 : } else if (internals->mode == BONDING_MODE_TLB
119 [ # # ]: 0 : || internals->mode == BONDING_MODE_ALB)
120 : 0 : bond_tlb_disable(internals);
121 : :
122 : 0 : member_pos = find_member_by_id(internals->active_members, active_count,
123 : : port_id);
124 : :
125 : : /*
126 : : * If member was not at the end of the list
127 : : * shift active members up active array list.
128 : : */
129 [ # # ]: 0 : if (member_pos < active_count) {
130 : 0 : active_count--;
131 : 0 : memmove(internals->active_members + member_pos,
132 : 0 : internals->active_members + member_pos + 1,
133 : 0 : (active_count - member_pos) *
134 : : sizeof(internals->active_members[0]));
135 : : }
136 : :
137 : : RTE_ASSERT(active_count < RTE_DIM(internals->active_members));
138 : 0 : internals->active_member_count = active_count;
139 : :
140 [ # # ]: 0 : if (eth_dev->data->dev_started) {
141 [ # # ]: 0 : if (internals->mode == BONDING_MODE_8023AD) {
142 : 0 : bond_mode_8023ad_start(eth_dev);
143 [ # # ]: 0 : } else if (internals->mode == BONDING_MODE_TLB) {
144 : 0 : bond_tlb_enable(internals);
145 [ # # ]: 0 : } else if (internals->mode == BONDING_MODE_ALB) {
146 : 0 : bond_tlb_enable(internals);
147 : 0 : bond_mode_alb_client_list_upd(eth_dev);
148 : : }
149 : : }
150 : 0 : }
151 : :
152 : : int
153 : 0 : rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
154 : : {
155 : : struct bond_dev_private *internals;
156 : : struct rte_eth_dev *bond_dev;
157 : : char devargs[52];
158 : : int ret;
159 : :
160 [ # # ]: 0 : if (name == NULL) {
161 : 0 : RTE_BOND_LOG(ERR, "Invalid name specified");
162 : 0 : return -EINVAL;
163 : : }
164 : :
165 [ # # ]: 0 : ret = snprintf(devargs, sizeof(devargs),
166 : : "driver=net_bonding,mode=%d,socket_id=%d", mode, socket_id);
167 [ # # ]: 0 : if (ret < 0 || ret >= (int)sizeof(devargs))
168 : : return -ENOMEM;
169 : :
170 : 0 : ret = rte_vdev_init(name, devargs);
171 [ # # ]: 0 : if (ret)
172 : : return ret;
173 : :
174 : 0 : bond_dev = rte_eth_dev_get_by_name(name);
175 : : RTE_ASSERT(bond_dev);
176 : :
177 : : /*
178 : : * To make bond_ethdev_configure() happy we need to free the
179 : : * internals->kvlist here.
180 : : *
181 : : * Also see comment in bond_ethdev_configure().
182 : : */
183 : 0 : internals = bond_dev->data->dev_private;
184 : 0 : rte_kvargs_free(internals->kvlist);
185 : 0 : internals->kvlist = NULL;
186 : :
187 : 0 : return bond_dev->data->port_id;
188 : : }
189 : :
190 : : int
191 : 0 : rte_eth_bond_free(const char *name)
192 : : {
193 : 0 : return rte_vdev_uninit(name);
194 : : }
195 : :
196 : : static int
197 : 0 : member_vlan_filter_set(uint16_t bonding_port_id, uint16_t member_port_id)
198 : : {
199 : : struct rte_eth_dev *bonding_eth_dev;
200 : : struct bond_dev_private *internals;
201 : : int found;
202 : : int res = 0;
203 : 0 : uint64_t slab = 0;
204 : 0 : uint32_t pos = 0;
205 : : uint16_t first;
206 : :
207 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
208 [ # # ]: 0 : if ((bonding_eth_dev->data->dev_conf.rxmode.offloads &
209 : : RTE_ETH_RX_OFFLOAD_VLAN_FILTER) == 0)
210 : : return 0;
211 : :
212 : 0 : internals = bonding_eth_dev->data->dev_private;
213 : 0 : found = rte_bitmap_scan(internals->vlan_filter_bmp, &pos, &slab);
214 : 0 : first = pos;
215 : :
216 [ # # ]: 0 : if (!found)
217 : : return 0;
218 : :
219 : : do {
220 : : uint32_t i;
221 : : uint64_t mask;
222 : :
223 : 0 : for (i = 0, mask = 1;
224 [ # # ]: 0 : i < RTE_BITMAP_SLAB_BIT_SIZE;
225 : 0 : i ++, mask <<= 1) {
226 [ # # ]: 0 : if (unlikely(slab & mask)) {
227 : 0 : uint16_t vlan_id = pos + i;
228 : :
229 : 0 : res = rte_eth_dev_vlan_filter(member_port_id,
230 : : vlan_id, 1);
231 : : }
232 : : }
233 : 0 : found = rte_bitmap_scan(internals->vlan_filter_bmp,
234 : : &pos, &slab);
235 [ # # # # : 0 : } while (found && first != pos && res == 0);
# # ]
236 : :
237 : : return res;
238 : : }
239 : :
240 : : static int
241 : 0 : member_rte_flow_prepare(uint16_t member_id, struct bond_dev_private *internals)
242 : : {
243 : : struct rte_flow *flow;
244 : : struct rte_flow_error ferror;
245 : 0 : uint16_t member_port_id = internals->members[member_id].port_id;
246 : :
247 [ # # ]: 0 : if (internals->flow_isolated_valid != 0) {
248 [ # # ]: 0 : if (rte_eth_dev_stop(member_port_id) != 0) {
249 : 0 : RTE_BOND_LOG(ERR, "Failed to stop device on port %u",
250 : : member_port_id);
251 : 0 : return -1;
252 : : }
253 : :
254 [ # # ]: 0 : if (rte_flow_isolate(member_port_id, internals->flow_isolated,
255 : : &ferror)) {
256 [ # # ]: 0 : RTE_BOND_LOG(ERR, "rte_flow_isolate failed for member"
257 : : " %d: %s", member_id, ferror.message ?
258 : : ferror.message : "(no stated reason)");
259 : 0 : return -1;
260 : : }
261 : : }
262 [ # # ]: 0 : TAILQ_FOREACH(flow, &internals->flow_list, next) {
263 : 0 : flow->flows[member_id] = rte_flow_create(member_port_id,
264 : 0 : flow->rule.attr,
265 : 0 : flow->rule.pattern,
266 : 0 : flow->rule.actions,
267 : : &ferror);
268 [ # # ]: 0 : if (flow->flows[member_id] == NULL) {
269 [ # # ]: 0 : RTE_BOND_LOG(ERR, "Cannot create flow for member"
270 : : " %d: %s", member_id,
271 : : ferror.message ? ferror.message :
272 : : "(no stated reason)");
273 : : /* Destroy successful bond flows from the member */
274 [ # # ]: 0 : TAILQ_FOREACH(flow, &internals->flow_list, next) {
275 [ # # ]: 0 : if (flow->flows[member_id] != NULL) {
276 : 0 : rte_flow_destroy(member_port_id,
277 : : flow->flows[member_id],
278 : : &ferror);
279 : 0 : flow->flows[member_id] = NULL;
280 : : }
281 : : }
282 : : return -1;
283 : : }
284 : : }
285 : : return 0;
286 : : }
287 : :
288 : : static void
289 : 0 : eth_bond_member_inherit_dev_info_rx_first(struct bond_dev_private *internals,
290 : : const struct rte_eth_dev_info *di)
291 : : {
292 : 0 : struct rte_eth_rxconf *rxconf_i = &internals->default_rxconf;
293 : :
294 : 0 : internals->reta_size = di->reta_size;
295 : 0 : internals->rss_key_len = di->hash_key_size;
296 : :
297 : : /* Inherit Rx offload capabilities from the first member device */
298 : 0 : internals->rx_offload_capa = di->rx_offload_capa;
299 : 0 : internals->rx_queue_offload_capa = di->rx_queue_offload_capa;
300 : 0 : internals->flow_type_rss_offloads = di->flow_type_rss_offloads;
301 : :
302 : : /* Inherit maximum Rx packet size from the first member device */
303 : 0 : internals->candidate_max_rx_pktlen = di->max_rx_pktlen;
304 : :
305 : : /* Inherit default Rx queue settings from the first member device */
306 : 0 : memcpy(rxconf_i, &di->default_rxconf, sizeof(*rxconf_i));
307 : :
308 : : /*
309 : : * Turn off descriptor prefetch and writeback by default for all
310 : : * member devices. Applications may tweak this setting if need be.
311 : : */
312 : 0 : rxconf_i->rx_thresh.pthresh = 0;
313 : 0 : rxconf_i->rx_thresh.hthresh = 0;
314 : 0 : rxconf_i->rx_thresh.wthresh = 0;
315 : :
316 : : /* Setting this to zero should effectively enable default values */
317 : 0 : rxconf_i->rx_free_thresh = 0;
318 : :
319 : : /* Disable deferred start by default for all member devices */
320 : 0 : rxconf_i->rx_deferred_start = 0;
321 : 0 : }
322 : :
323 : : static void
324 : : eth_bond_member_inherit_dev_info_tx_first(struct bond_dev_private *internals,
325 : : const struct rte_eth_dev_info *di)
326 : : {
327 : 0 : struct rte_eth_txconf *txconf_i = &internals->default_txconf;
328 : :
329 : : /* Inherit Tx offload capabilities from the first member device */
330 : 0 : internals->tx_offload_capa = di->tx_offload_capa;
331 : 0 : internals->tx_queue_offload_capa = di->tx_queue_offload_capa;
332 : :
333 : : /* Inherit default Tx queue settings from the first member device */
334 : : memcpy(txconf_i, &di->default_txconf, sizeof(*txconf_i));
335 : :
336 : : /*
337 : : * Turn off descriptor prefetch and writeback by default for all
338 : : * member devices. Applications may tweak this setting if need be.
339 : : */
340 : 0 : txconf_i->tx_thresh.pthresh = 0;
341 : 0 : txconf_i->tx_thresh.hthresh = 0;
342 : 0 : txconf_i->tx_thresh.wthresh = 0;
343 : :
344 : : /*
345 : : * Setting these parameters to zero assumes that default
346 : : * values will be configured implicitly by member devices.
347 : : */
348 : 0 : txconf_i->tx_free_thresh = 0;
349 : 0 : txconf_i->tx_rs_thresh = 0;
350 : :
351 : : /* Disable deferred start by default for all member devices */
352 : 0 : txconf_i->tx_deferred_start = 0;
353 : : }
354 : :
355 : : static void
356 : 0 : eth_bond_member_inherit_dev_info_rx_next(struct bond_dev_private *internals,
357 : : const struct rte_eth_dev_info *di)
358 : : {
359 : : struct rte_eth_rxconf *rxconf_i = &internals->default_rxconf;
360 : : const struct rte_eth_rxconf *rxconf = &di->default_rxconf;
361 : :
362 : 0 : internals->rx_offload_capa &= di->rx_offload_capa;
363 : 0 : internals->rx_queue_offload_capa &= di->rx_queue_offload_capa;
364 : 0 : internals->flow_type_rss_offloads &= di->flow_type_rss_offloads;
365 : :
366 : : /*
367 : : * If at least one member device suggests enabling this
368 : : * setting by default, enable it for all member devices
369 : : * since disabling it may not be necessarily supported.
370 : : */
371 [ # # ]: 0 : if (rxconf->rx_drop_en == 1)
372 : 0 : rxconf_i->rx_drop_en = 1;
373 : :
374 : : /*
375 : : * Adding a new member device may cause some of previously inherited
376 : : * offloads to be withdrawn from the internal rx_queue_offload_capa
377 : : * value. Thus, the new internal value of default Rx queue offloads
378 : : * has to be masked by rx_queue_offload_capa to make sure that only
379 : : * commonly supported offloads are preserved from both the previous
380 : : * value and the value being inherited from the new member device.
381 : : */
382 : 0 : rxconf_i->offloads = (rxconf_i->offloads | rxconf->offloads) &
383 : : internals->rx_queue_offload_capa;
384 : :
385 : : /*
386 : : * RETA size is GCD of all members RETA sizes, so, if all sizes will be
387 : : * the power of 2, the lower one is GCD
388 : : */
389 [ # # ]: 0 : if (internals->reta_size > di->reta_size)
390 : 0 : internals->reta_size = di->reta_size;
391 [ # # ]: 0 : if (internals->rss_key_len > di->hash_key_size) {
392 : 0 : RTE_BOND_LOG(WARNING, "member has different rss key size, "
393 : : "configuring rss may fail");
394 : 0 : internals->rss_key_len = di->hash_key_size;
395 : : }
396 : :
397 [ # # ]: 0 : if (!internals->max_rx_pktlen &&
398 [ # # ]: 0 : di->max_rx_pktlen < internals->candidate_max_rx_pktlen)
399 : 0 : internals->candidate_max_rx_pktlen = di->max_rx_pktlen;
400 : 0 : }
401 : :
402 : : static void
403 : : eth_bond_member_inherit_dev_info_tx_next(struct bond_dev_private *internals,
404 : : const struct rte_eth_dev_info *di)
405 : : {
406 : : struct rte_eth_txconf *txconf_i = &internals->default_txconf;
407 : : const struct rte_eth_txconf *txconf = &di->default_txconf;
408 : :
409 : 0 : internals->tx_offload_capa &= di->tx_offload_capa;
410 : 0 : internals->tx_queue_offload_capa &= di->tx_queue_offload_capa;
411 : :
412 : : /*
413 : : * Adding a new member device may cause some of previously inherited
414 : : * offloads to be withdrawn from the internal tx_queue_offload_capa
415 : : * value. Thus, the new internal value of default Tx queue offloads
416 : : * has to be masked by tx_queue_offload_capa to make sure that only
417 : : * commonly supported offloads are preserved from both the previous
418 : : * value and the value being inherited from the new member device.
419 : : */
420 : 0 : txconf_i->offloads = (txconf_i->offloads | txconf->offloads) &
421 : : internals->tx_queue_offload_capa;
422 : : }
423 : :
424 : : static void
425 : : eth_bond_member_inherit_desc_lim_first(struct rte_eth_desc_lim *bond_desc_lim,
426 : : const struct rte_eth_desc_lim *member_desc_lim)
427 : : {
428 : : memcpy(bond_desc_lim, member_desc_lim, sizeof(*bond_desc_lim));
429 : 0 : }
430 : :
431 : : static int
432 : 0 : eth_bond_member_inherit_desc_lim_next(struct rte_eth_desc_lim *bond_desc_lim,
433 : : const struct rte_eth_desc_lim *member_desc_lim)
434 : : {
435 : 0 : bond_desc_lim->nb_max = RTE_MIN(bond_desc_lim->nb_max,
436 : : member_desc_lim->nb_max);
437 : 0 : bond_desc_lim->nb_min = RTE_MAX(bond_desc_lim->nb_min,
438 : : member_desc_lim->nb_min);
439 : 0 : bond_desc_lim->nb_align = RTE_MAX(bond_desc_lim->nb_align,
440 : : member_desc_lim->nb_align);
441 : :
442 [ # # # # ]: 0 : if (bond_desc_lim->nb_min > bond_desc_lim->nb_max ||
443 : : bond_desc_lim->nb_align > bond_desc_lim->nb_max) {
444 : 0 : RTE_BOND_LOG(ERR, "Failed to inherit descriptor limits");
445 : 0 : return -EINVAL;
446 : : }
447 : :
448 : : /* Treat maximum number of segments equal to 0 as unspecified */
449 [ # # ]: 0 : if (member_desc_lim->nb_seg_max != 0 &&
450 [ # # # # ]: 0 : (bond_desc_lim->nb_seg_max == 0 ||
451 : : member_desc_lim->nb_seg_max < bond_desc_lim->nb_seg_max))
452 : 0 : bond_desc_lim->nb_seg_max = member_desc_lim->nb_seg_max;
453 [ # # ]: 0 : if (member_desc_lim->nb_mtu_seg_max != 0 &&
454 [ # # # # ]: 0 : (bond_desc_lim->nb_mtu_seg_max == 0 ||
455 : : member_desc_lim->nb_mtu_seg_max < bond_desc_lim->nb_mtu_seg_max))
456 : 0 : bond_desc_lim->nb_mtu_seg_max = member_desc_lim->nb_mtu_seg_max;
457 : :
458 : : return 0;
459 : : }
460 : :
461 : : static int
462 : 0 : __eth_bond_member_add_lock_free(uint16_t bonding_port_id, uint16_t member_port_id)
463 : : {
464 : : struct rte_eth_dev *bonding_eth_dev, *member_eth_dev;
465 : : struct bond_dev_private *internals;
466 : : struct rte_eth_link link_props;
467 : : struct rte_eth_dev_info dev_info;
468 : : int ret;
469 : :
470 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
471 : 0 : internals = bonding_eth_dev->data->dev_private;
472 : :
473 [ # # ]: 0 : if (valid_member_port_id(internals, member_port_id) != 0)
474 : : return -1;
475 : :
476 : 0 : member_eth_dev = &rte_eth_devices[member_port_id];
477 [ # # ]: 0 : if (member_eth_dev->data->dev_flags & RTE_ETH_DEV_BONDING_MEMBER) {
478 : 0 : RTE_BOND_LOG(ERR, "Member device is already a member of a bonding device");
479 : 0 : return -1;
480 : : }
481 : :
482 : 0 : ret = rte_eth_dev_info_get(member_port_id, &dev_info);
483 [ # # ]: 0 : if (ret != 0) {
484 : 0 : RTE_BOND_LOG(ERR,
485 : : "%s: Error during getting device (port %u) info: %s\n",
486 : : __func__, member_port_id, strerror(-ret));
487 : :
488 : 0 : return ret;
489 : : }
490 [ # # ]: 0 : if (dev_info.max_rx_pktlen < internals->max_rx_pktlen) {
491 : 0 : RTE_BOND_LOG(ERR, "Member (port %u) max_rx_pktlen too small",
492 : : member_port_id);
493 : 0 : return -1;
494 : : }
495 : :
496 : 0 : member_add(internals, member_eth_dev);
497 : :
498 : : /* We need to store members reta_size to be able to synchronize RETA for all
499 : : * member devices even if its sizes are different.
500 : : */
501 : 0 : internals->members[internals->member_count].reta_size = dev_info.reta_size;
502 : :
503 [ # # ]: 0 : if (internals->member_count < 1) {
504 : : /*
505 : : * if MAC is not user defined then use MAC of first member add to
506 : : * bonding device.
507 : : */
508 [ # # ]: 0 : if (!internals->user_defined_mac) {
509 [ # # ]: 0 : if (mac_address_set(bonding_eth_dev,
510 : 0 : member_eth_dev->data->mac_addrs)) {
511 : 0 : RTE_BOND_LOG(ERR, "Failed to set MAC address");
512 : 0 : return -1;
513 : : }
514 : : }
515 : :
516 : : /* Make primary member */
517 : 0 : internals->primary_port = member_port_id;
518 : 0 : internals->current_primary_port = member_port_id;
519 : :
520 : 0 : internals->speed_capa = dev_info.speed_capa;
521 : :
522 : : /* Inherit queues settings from first member */
523 : 0 : internals->nb_rx_queues = member_eth_dev->data->nb_rx_queues;
524 : 0 : internals->nb_tx_queues = member_eth_dev->data->nb_tx_queues;
525 : :
526 : 0 : eth_bond_member_inherit_dev_info_rx_first(internals, &dev_info);
527 : : eth_bond_member_inherit_dev_info_tx_first(internals, &dev_info);
528 : :
529 : 0 : eth_bond_member_inherit_desc_lim_first(&internals->rx_desc_lim,
530 : : &dev_info.rx_desc_lim);
531 : 0 : eth_bond_member_inherit_desc_lim_first(&internals->tx_desc_lim,
532 : : &dev_info.tx_desc_lim);
533 : : } else {
534 : : int ret;
535 : :
536 : 0 : internals->speed_capa &= dev_info.speed_capa;
537 : 0 : eth_bond_member_inherit_dev_info_rx_next(internals, &dev_info);
538 : : eth_bond_member_inherit_dev_info_tx_next(internals, &dev_info);
539 : :
540 : 0 : ret = eth_bond_member_inherit_desc_lim_next(&internals->rx_desc_lim,
541 : : &dev_info.rx_desc_lim);
542 [ # # ]: 0 : if (ret != 0)
543 : : return ret;
544 : :
545 : 0 : ret = eth_bond_member_inherit_desc_lim_next(&internals->tx_desc_lim,
546 : : &dev_info.tx_desc_lim);
547 [ # # ]: 0 : if (ret != 0)
548 : : return ret;
549 : : }
550 : :
551 : : /* Bond mode Broadcast & 8023AD don't support MBUF_FAST_FREE offload. */
552 [ # # ]: 0 : if (internals->mode == BONDING_MODE_8023AD ||
553 : : internals->mode == BONDING_MODE_BROADCAST)
554 : 0 : internals->tx_offload_capa &= ~RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
555 : :
556 : 0 : bonding_eth_dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf &=
557 : 0 : internals->flow_type_rss_offloads;
558 : :
559 [ # # ]: 0 : if (member_rte_flow_prepare(internals->member_count, internals) != 0) {
560 : 0 : RTE_BOND_LOG(ERR, "Failed to prepare new member flows: port=%d",
561 : : member_port_id);
562 : 0 : return -1;
563 : : }
564 : :
565 : : /* Add additional MAC addresses to the member */
566 [ # # ]: 0 : if (member_add_mac_addresses(bonding_eth_dev, member_port_id) != 0) {
567 : 0 : RTE_BOND_LOG(ERR, "Failed to add mac address(es) to member %hu",
568 : : member_port_id);
569 : 0 : return -1;
570 : : }
571 : :
572 : 0 : internals->member_count++;
573 : :
574 [ # # ]: 0 : if (bonding_eth_dev->data->dev_started) {
575 [ # # ]: 0 : if (member_configure(bonding_eth_dev, member_eth_dev) != 0) {
576 : 0 : internals->member_count--;
577 : 0 : RTE_BOND_LOG(ERR, "rte_bond_members_configure: port=%d",
578 : : member_port_id);
579 : 0 : return -1;
580 : : }
581 [ # # ]: 0 : if (member_start(bonding_eth_dev, member_eth_dev) != 0) {
582 : 0 : internals->member_count--;
583 : 0 : RTE_BOND_LOG(ERR, "rte_bond_members_start: port=%d",
584 : : member_port_id);
585 : 0 : return -1;
586 : : }
587 : : }
588 : :
589 : : /* Update all member devices MACs */
590 : 0 : mac_address_members_update(bonding_eth_dev);
591 : :
592 : : /*
593 : : * Register link status change callback with bonding device pointer as
594 : : * argument.
595 : : */
596 : 0 : rte_eth_dev_callback_register(member_port_id, RTE_ETH_EVENT_INTR_LSC,
597 : 0 : bond_ethdev_lsc_event_callback, &bonding_eth_dev->data->port_id);
598 : :
599 : : /*
600 : : * If bonding device is started then we can add the member to our active
601 : : * member array.
602 : : */
603 [ # # ]: 0 : if (bonding_eth_dev->data->dev_started) {
604 : 0 : ret = rte_eth_link_get_nowait(member_port_id, &link_props);
605 [ # # ]: 0 : if (ret < 0) {
606 : 0 : rte_eth_dev_callback_unregister(member_port_id,
607 : : RTE_ETH_EVENT_INTR_LSC,
608 : : bond_ethdev_lsc_event_callback,
609 : 0 : &bonding_eth_dev->data->port_id);
610 : 0 : internals->member_count--;
611 : 0 : RTE_BOND_LOG(ERR,
612 : : "Member (port %u) link get failed: %s\n",
613 : : member_port_id, rte_strerror(-ret));
614 : 0 : return -1;
615 : : }
616 : :
617 [ # # ]: 0 : if (link_props.link_status == RTE_ETH_LINK_UP) {
618 [ # # ]: 0 : if (internals->active_member_count == 0 &&
619 [ # # ]: 0 : !internals->user_defined_primary_port)
620 : 0 : bond_ethdev_primary_set(internals,
621 : : member_port_id);
622 : : }
623 : : }
624 : :
625 : : /* Add member details to bonding device */
626 : 0 : member_eth_dev->data->dev_flags |= RTE_ETH_DEV_BONDING_MEMBER;
627 : :
628 : 0 : member_vlan_filter_set(bonding_port_id, member_port_id);
629 : :
630 : 0 : return 0;
631 : :
632 : : }
633 : :
634 : : int
635 : 0 : rte_eth_bond_member_add(uint16_t bonding_port_id, uint16_t member_port_id)
636 : : {
637 : : struct rte_eth_dev *bonding_eth_dev;
638 : : struct bond_dev_private *internals;
639 : :
640 : : int retval;
641 : :
642 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
643 : : return -1;
644 : :
645 : : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
646 : 0 : internals = bonding_eth_dev->data->dev_private;
647 : :
648 [ # # ]: 0 : if (valid_member_port_id(internals, member_port_id) != 0)
649 : : return -1;
650 : :
651 : 0 : rte_spinlock_lock(&internals->lock);
652 : :
653 : 0 : retval = __eth_bond_member_add_lock_free(bonding_port_id, member_port_id);
654 : :
655 : : rte_spinlock_unlock(&internals->lock);
656 : :
657 : 0 : return retval;
658 : : }
659 : :
660 : : static int
661 : 0 : __eth_bond_member_remove_lock_free(uint16_t bonding_port_id,
662 : : uint16_t member_port_id)
663 : : {
664 : : struct rte_eth_dev *bonding_eth_dev;
665 : : struct bond_dev_private *internals;
666 : : struct rte_eth_dev *member_eth_dev;
667 : : struct rte_flow_error flow_error;
668 : : struct rte_flow *flow;
669 : : int i, member_idx;
670 : :
671 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
672 : 0 : internals = bonding_eth_dev->data->dev_private;
673 : :
674 [ # # ]: 0 : if (valid_member_port_id(internals, member_port_id) < 0)
675 : : return -1;
676 : :
677 : : /* first remove from active member list */
678 : 0 : member_idx = find_member_by_id(internals->active_members,
679 : 0 : internals->active_member_count, member_port_id);
680 : :
681 [ # # ]: 0 : if (member_idx < internals->active_member_count)
682 : 0 : deactivate_member(bonding_eth_dev, member_port_id);
683 : :
684 : : member_idx = -1;
685 : : /* now find in member list */
686 [ # # ]: 0 : for (i = 0; i < internals->member_count; i++)
687 [ # # ]: 0 : if (internals->members[i].port_id == member_port_id) {
688 : : member_idx = i;
689 : : break;
690 : : }
691 : :
692 [ # # ]: 0 : if (member_idx < 0) {
693 : 0 : RTE_BOND_LOG(ERR, "Could not find member in port list, member count %u",
694 : : internals->member_count);
695 : 0 : return -1;
696 : : }
697 : :
698 : : /* Un-register link status change callback with bonding device pointer as
699 : : * argument*/
700 : 0 : rte_eth_dev_callback_unregister(member_port_id, RTE_ETH_EVENT_INTR_LSC,
701 : : bond_ethdev_lsc_event_callback,
702 : 0 : &rte_eth_devices[bonding_port_id].data->port_id);
703 : :
704 : : /* Restore original MAC address of member device */
705 : 0 : rte_eth_dev_default_mac_addr_set(member_port_id,
706 : : &internals->members[member_idx].persisted_mac_addr);
707 : :
708 : : /* remove additional MAC addresses from the member */
709 : 0 : member_remove_mac_addresses(bonding_eth_dev, member_port_id);
710 : :
711 : : /*
712 : : * Remove bond device flows from member device.
713 : : * Note: don't restore flow isolate mode.
714 : : */
715 [ # # ]: 0 : TAILQ_FOREACH(flow, &internals->flow_list, next) {
716 [ # # ]: 0 : if (flow->flows[member_idx] != NULL) {
717 : 0 : rte_flow_destroy(member_port_id, flow->flows[member_idx],
718 : : &flow_error);
719 : 0 : flow->flows[member_idx] = NULL;
720 : : }
721 : : }
722 : :
723 : : /* Remove the dedicated queues flow */
724 [ # # ]: 0 : if (internals->mode == BONDING_MODE_8023AD &&
725 [ # # ]: 0 : internals->mode4.dedicated_queues.enabled == 1 &&
726 [ # # ]: 0 : internals->mode4.dedicated_queues.flow[member_port_id] != NULL) {
727 : 0 : rte_flow_destroy(member_port_id,
728 : : internals->mode4.dedicated_queues.flow[member_port_id],
729 : : &flow_error);
730 : 0 : internals->mode4.dedicated_queues.flow[member_port_id] = NULL;
731 : : }
732 : :
733 : 0 : member_eth_dev = &rte_eth_devices[member_port_id];
734 : 0 : member_remove(internals, member_eth_dev);
735 : 0 : member_eth_dev->data->dev_flags &= (~RTE_ETH_DEV_BONDING_MEMBER);
736 : :
737 : : /* first member in the active list will be the primary by default,
738 : : * otherwise use first device in list */
739 [ # # ]: 0 : if (internals->current_primary_port == member_port_id) {
740 [ # # ]: 0 : if (internals->active_member_count > 0)
741 : 0 : internals->current_primary_port = internals->active_members[0];
742 [ # # ]: 0 : else if (internals->member_count > 0)
743 : 0 : internals->current_primary_port = internals->members[0].port_id;
744 : : else
745 : 0 : internals->primary_port = 0;
746 : 0 : mac_address_members_update(bonding_eth_dev);
747 : : }
748 : :
749 [ # # ]: 0 : if (internals->active_member_count < 1) {
750 : : /*
751 : : * if no members are any longer attached to bonding device and MAC is not
752 : : * user defined then clear MAC of bonding device as it will be reset
753 : : * when a new member is added.
754 : : */
755 [ # # # # ]: 0 : if (internals->member_count < 1 && !internals->user_defined_mac)
756 : 0 : memset(rte_eth_devices[bonding_port_id].data->mac_addrs, 0,
757 : : sizeof(*rte_eth_devices[bonding_port_id].data->mac_addrs));
758 : : }
759 [ # # ]: 0 : if (internals->member_count == 0) {
760 : 0 : internals->rx_offload_capa = 0;
761 : 0 : internals->tx_offload_capa = 0;
762 : 0 : internals->rx_queue_offload_capa = 0;
763 : 0 : internals->tx_queue_offload_capa = 0;
764 : 0 : internals->flow_type_rss_offloads = RTE_ETH_RSS_PROTO_MASK;
765 : 0 : internals->reta_size = 0;
766 : 0 : internals->candidate_max_rx_pktlen = 0;
767 : 0 : internals->max_rx_pktlen = 0;
768 : : }
769 : : return 0;
770 : : }
771 : :
772 : : int
773 : 0 : rte_eth_bond_member_remove(uint16_t bonding_port_id, uint16_t member_port_id)
774 : : {
775 : : struct rte_eth_dev *bonding_eth_dev;
776 : : struct bond_dev_private *internals;
777 : : int retval;
778 : :
779 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
780 : : return -1;
781 : :
782 : : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
783 : 0 : internals = bonding_eth_dev->data->dev_private;
784 : :
785 : 0 : rte_spinlock_lock(&internals->lock);
786 : :
787 : 0 : retval = __eth_bond_member_remove_lock_free(bonding_port_id, member_port_id);
788 : :
789 : : rte_spinlock_unlock(&internals->lock);
790 : :
791 : 0 : return retval;
792 : : }
793 : :
794 : : int
795 : 0 : rte_eth_bond_mode_set(uint16_t bonding_port_id, uint8_t mode)
796 : : {
797 : : struct rte_eth_dev *bonding_eth_dev;
798 : :
799 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
800 : : return -1;
801 : :
802 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
803 : :
804 [ # # # # ]: 0 : if (check_for_main_bonding_ethdev(bonding_eth_dev) != 0 &&
805 : : mode == BONDING_MODE_8023AD)
806 : : return -1;
807 : :
808 : 0 : return bond_ethdev_mode_set(bonding_eth_dev, mode);
809 : : }
810 : :
811 : : int
812 : 0 : rte_eth_bond_mode_get(uint16_t bonding_port_id)
813 : : {
814 : : struct bond_dev_private *internals;
815 : :
816 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
817 : : return -1;
818 : :
819 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
820 : :
821 : 0 : return internals->mode;
822 : : }
823 : :
824 : : int
825 : 0 : rte_eth_bond_primary_set(uint16_t bonding_port_id, uint16_t member_port_id)
826 : : {
827 : : struct bond_dev_private *internals;
828 : :
829 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
830 : : return -1;
831 : :
832 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
833 : :
834 [ # # ]: 0 : if (valid_member_port_id(internals, member_port_id) != 0)
835 : : return -1;
836 : :
837 : 0 : internals->user_defined_primary_port = 1;
838 : 0 : internals->primary_port = member_port_id;
839 : :
840 : 0 : bond_ethdev_primary_set(internals, member_port_id);
841 : :
842 : 0 : return 0;
843 : : }
844 : :
845 : : int
846 : 0 : rte_eth_bond_primary_get(uint16_t bonding_port_id)
847 : : {
848 : : struct bond_dev_private *internals;
849 : :
850 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
851 : : return -1;
852 : :
853 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
854 : :
855 [ # # ]: 0 : if (internals->member_count < 1)
856 : : return -1;
857 : :
858 : 0 : return internals->current_primary_port;
859 : : }
860 : :
861 : : int
862 : 0 : rte_eth_bond_members_get(uint16_t bonding_port_id, uint16_t members[],
863 : : uint16_t len)
864 : : {
865 : : struct bond_dev_private *internals;
866 : : uint16_t i;
867 : :
868 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
869 : : return -1;
870 : :
871 [ # # ]: 0 : if (members == NULL)
872 : : return -1;
873 : :
874 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
875 : :
876 [ # # ]: 0 : if (internals->member_count > len)
877 : : return -1;
878 : :
879 [ # # ]: 0 : for (i = 0; i < internals->member_count; i++)
880 : 0 : members[i] = internals->members[i].port_id;
881 : :
882 : 0 : return internals->member_count;
883 : : }
884 : :
885 : : int
886 : 0 : rte_eth_bond_active_members_get(uint16_t bonding_port_id, uint16_t members[],
887 : : uint16_t len)
888 : : {
889 : : struct bond_dev_private *internals;
890 : :
891 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
892 : : return -1;
893 : :
894 [ # # ]: 0 : if (members == NULL)
895 : : return -1;
896 : :
897 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
898 : :
899 [ # # ]: 0 : if (internals->active_member_count > len)
900 : : return -1;
901 : :
902 : 0 : memcpy(members, internals->active_members,
903 : 0 : internals->active_member_count * sizeof(internals->active_members[0]));
904 : :
905 : 0 : return internals->active_member_count;
906 : : }
907 : :
908 : : int
909 : 0 : rte_eth_bond_mac_address_set(uint16_t bonding_port_id,
910 : : struct rte_ether_addr *mac_addr)
911 : : {
912 : : struct rte_eth_dev *bonding_eth_dev;
913 : : struct bond_dev_private *internals;
914 : :
915 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
916 : : return -1;
917 : :
918 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
919 : 0 : internals = bonding_eth_dev->data->dev_private;
920 : :
921 : : /* Set MAC Address of Bonding Device */
922 [ # # ]: 0 : if (mac_address_set(bonding_eth_dev, mac_addr))
923 : : return -1;
924 : :
925 : 0 : internals->user_defined_mac = 1;
926 : :
927 : : /* Update all member devices MACs*/
928 [ # # ]: 0 : if (internals->member_count > 0)
929 : 0 : return mac_address_members_update(bonding_eth_dev);
930 : :
931 : : return 0;
932 : : }
933 : :
934 : : int
935 : 0 : rte_eth_bond_mac_address_reset(uint16_t bonding_port_id)
936 : : {
937 : : struct rte_eth_dev *bonding_eth_dev;
938 : : struct bond_dev_private *internals;
939 : :
940 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
941 : : return -1;
942 : :
943 : 0 : bonding_eth_dev = &rte_eth_devices[bonding_port_id];
944 : 0 : internals = bonding_eth_dev->data->dev_private;
945 : :
946 : 0 : internals->user_defined_mac = 0;
947 : :
948 [ # # ]: 0 : if (internals->member_count > 0) {
949 : : int member_port;
950 : : /* Get the primary member location based on the primary port
951 : : * number as, while member_add(), we will keep the primary
952 : : * member based on member_count,but not based on the primary port.
953 : : */
954 [ # # ]: 0 : for (member_port = 0; member_port < internals->member_count;
955 : 0 : member_port++) {
956 : 0 : if (internals->members[member_port].port_id ==
957 [ # # ]: 0 : internals->primary_port)
958 : : break;
959 : : }
960 : :
961 : : /* Set MAC Address of Bonding Device */
962 [ # # ]: 0 : if (mac_address_set(bonding_eth_dev,
963 : : &internals->members[member_port].persisted_mac_addr)
964 : : != 0) {
965 : 0 : RTE_BOND_LOG(ERR, "Failed to set MAC address on bonding device");
966 : 0 : return -1;
967 : : }
968 : : /* Update all member devices MAC addresses */
969 : 0 : return mac_address_members_update(bonding_eth_dev);
970 : : }
971 : : /* No need to update anything as no members present */
972 : : return 0;
973 : : }
974 : :
975 : : int
976 : 0 : rte_eth_bond_xmit_policy_set(uint16_t bonding_port_id, uint8_t policy)
977 : : {
978 : : struct bond_dev_private *internals;
979 : :
980 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
981 : : return -1;
982 : :
983 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
984 : :
985 [ # # # # ]: 0 : switch (policy) {
986 : 0 : case BALANCE_XMIT_POLICY_LAYER2:
987 : 0 : internals->balance_xmit_policy = policy;
988 : 0 : internals->burst_xmit_hash = burst_xmit_l2_hash;
989 : 0 : break;
990 : 0 : case BALANCE_XMIT_POLICY_LAYER23:
991 : 0 : internals->balance_xmit_policy = policy;
992 : 0 : internals->burst_xmit_hash = burst_xmit_l23_hash;
993 : 0 : break;
994 : 0 : case BALANCE_XMIT_POLICY_LAYER34:
995 : 0 : internals->balance_xmit_policy = policy;
996 : 0 : internals->burst_xmit_hash = burst_xmit_l34_hash;
997 : 0 : break;
998 : :
999 : : default:
1000 : : return -1;
1001 : : }
1002 : : return 0;
1003 : : }
1004 : :
1005 : : int
1006 : 0 : rte_eth_bond_xmit_policy_get(uint16_t bonding_port_id)
1007 : : {
1008 : : struct bond_dev_private *internals;
1009 : :
1010 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1011 : : return -1;
1012 : :
1013 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1014 : :
1015 : 0 : return internals->balance_xmit_policy;
1016 : : }
1017 : :
1018 : : int
1019 : 0 : rte_eth_bond_link_monitoring_set(uint16_t bonding_port_id, uint32_t internal_ms)
1020 : : {
1021 : : struct bond_dev_private *internals;
1022 : :
1023 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1024 : : return -1;
1025 : :
1026 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1027 : 0 : internals->link_status_polling_interval_ms = internal_ms;
1028 : :
1029 : 0 : return 0;
1030 : : }
1031 : :
1032 : : int
1033 : 0 : rte_eth_bond_link_monitoring_get(uint16_t bonding_port_id)
1034 : : {
1035 : : struct bond_dev_private *internals;
1036 : :
1037 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1038 : : return -1;
1039 : :
1040 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1041 : :
1042 : 0 : return internals->link_status_polling_interval_ms;
1043 : : }
1044 : :
1045 : : int
1046 : 0 : rte_eth_bond_link_down_prop_delay_set(uint16_t bonding_port_id,
1047 : : uint32_t delay_ms)
1048 : :
1049 : : {
1050 : : struct bond_dev_private *internals;
1051 : :
1052 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1053 : : return -1;
1054 : :
1055 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1056 : 0 : internals->link_down_delay_ms = delay_ms;
1057 : :
1058 : 0 : return 0;
1059 : : }
1060 : :
1061 : : int
1062 : 0 : rte_eth_bond_link_down_prop_delay_get(uint16_t bonding_port_id)
1063 : : {
1064 : : struct bond_dev_private *internals;
1065 : :
1066 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1067 : : return -1;
1068 : :
1069 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1070 : :
1071 : 0 : return internals->link_down_delay_ms;
1072 : : }
1073 : :
1074 : : int
1075 : 0 : rte_eth_bond_link_up_prop_delay_set(uint16_t bonding_port_id, uint32_t delay_ms)
1076 : :
1077 : : {
1078 : : struct bond_dev_private *internals;
1079 : :
1080 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1081 : : return -1;
1082 : :
1083 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1084 : 0 : internals->link_up_delay_ms = delay_ms;
1085 : :
1086 : 0 : return 0;
1087 : : }
1088 : :
1089 : : int
1090 : 0 : rte_eth_bond_link_up_prop_delay_get(uint16_t bonding_port_id)
1091 : : {
1092 : : struct bond_dev_private *internals;
1093 : :
1094 [ # # ]: 0 : if (valid_bonding_port_id(bonding_port_id) != 0)
1095 : : return -1;
1096 : :
1097 : 0 : internals = rte_eth_devices[bonding_port_id].data->dev_private;
1098 : :
1099 : 0 : return internals->link_up_delay_ms;
1100 : : }
|