@@ -180,6 +180,7 @@ struct bond_dev_private {
uint8_t member_update_idx;
bool kvargs_processing_is_done;
+ bool notify_member; /**< Enable member notification of bonding port. */
uint32_t candidate_max_rx_pktlen;
uint32_t max_rx_pktlen;
@@ -351,6 +351,52 @@ rte_eth_bond_link_up_prop_delay_set(uint16_t bonding_port_id,
int
rte_eth_bond_link_up_prop_delay_get(uint16_t bonding_port_id);
+/**
+ * Set the flag of whether bonding port notifies member ports.
+ *
+ * @param bonding_port_id
+ * Port ID of bonding device.
+ * @param notify
+ * Flag of whether bonding port notifies member ports.
+ *
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int
+rte_eth_bond_notify_member_flag_set(uint16_t bonding_port_id, bool notify);
+
+/**
+ * Get the flag of whether bonding port notifies member ports.
+ *
+ * @param bonding_port_id
+ * Port ID of bonding device.
+ * @param notify
+ * Flag of whether bonding port notifies member ports.
+ *
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int
+rte_eth_bond_notify_member_flag_get(uint16_t bonding_port_id, bool *notify);
+
+/**
+ * Notify the member ports of bonding port's information.
+ *
+ * This interface is called in the following functions:
+ * - bond_ethdev_lsc_event_callback()
+ * - bond_ethdev_configure()
+ *
+ * @param bonding_port_id
+ * Port ID of bonding device.
+ *
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int
+rte_eth_bond_notify_members(uint16_t bonding_port_id);
#ifdef __cplusplus
}
@@ -627,6 +627,17 @@ __eth_bond_member_add_lock_free(uint16_t bonding_port_id, uint16_t member_port_i
member_vlan_filter_set(bonding_port_id, member_port_id);
+ if (internals->notify_member &&
+ *member_eth_dev->dev_ops->bond_notify_member != NULL) {
+ ret = member_eth_dev->dev_ops->bond_notify_member(member_eth_dev,
+ bonding_eth_dev);
+ if (ret < 0) {
+ RTE_BOND_LOG(ERR, "Add member (port %u) notify failed!",
+ member_port_id);
+ return -1;
+ }
+ }
+
return 0;
}
@@ -733,6 +744,10 @@ __eth_bond_member_remove_lock_free(uint16_t bonding_port_id,
member_eth_dev = &rte_eth_devices[member_port_id];
member_remove(internals, member_eth_dev);
member_eth_dev->data->dev_flags &= (~RTE_ETH_DEV_BONDING_MEMBER);
+ if (internals->notify_member &&
+ *member_eth_dev->dev_ops->bond_notify_member != NULL)
+ member_eth_dev->dev_ops->bond_notify_member(member_eth_dev,
+ bonding_eth_dev);
/* first member in the active list will be the primary by default,
* otherwise use first device in list */
@@ -1098,3 +1113,60 @@ rte_eth_bond_link_up_prop_delay_get(uint16_t bonding_port_id)
return internals->link_up_delay_ms;
}
+
+int
+rte_eth_bond_notify_member_flag_set(uint16_t bonding_port_id, bool notify)
+{
+ struct bond_dev_private *internals;
+
+ if (valid_bonding_port_id(bonding_port_id) != 0)
+ return -EINVAL;
+
+ internals = rte_eth_devices[bonding_port_id].data->dev_private;
+
+ internals->notify_member = notify;
+
+ return 0;
+}
+
+int
+rte_eth_bond_notify_member_flag_get(uint16_t bonding_port_id, bool *notify)
+{
+ struct bond_dev_private *internals;
+
+ if (valid_bonding_port_id(bonding_port_id) != 0)
+ return -EINVAL;
+
+ internals = rte_eth_devices[bonding_port_id].data->dev_private;
+
+ *notify = internals->notify_member;
+
+ return 0;
+}
+
+int
+rte_eth_bond_notify_members(uint16_t bonding_port_id)
+{
+ uint32_t i;
+ uint16_t member_port_id;
+ struct rte_eth_dev *bond_dev;
+ struct rte_eth_dev *member_dev;
+ struct bond_dev_private *internals;
+
+ if (valid_bonding_port_id(bonding_port_id) != 0)
+ return -EINVAL;
+
+ bond_dev = &rte_eth_devices[bonding_port_id];
+ internals = bond_dev->data->dev_private;
+
+ for (i = 0; i < internals->member_count; i++) {
+ member_port_id = internals->members[i].port_id;
+ member_dev = &rte_eth_devices[member_port_id];
+ /* Notify member port if it supports. */
+ if (*member_dev->dev_ops->bond_notify_member != NULL)
+ member_dev->dev_ops->bond_notify_member(member_dev,
+ bond_dev);
+ }
+
+ return 0;
+}
@@ -2982,11 +2982,13 @@ bond_ethdev_lsc_event_callback(uint16_t port_id, enum rte_eth_event_type type,
int valid_member = 0;
uint16_t active_pos, member_idx;
uint16_t i;
+ uint16_t bonding_port_id;
if (type != RTE_ETH_EVENT_INTR_LSC || param == NULL)
return rc;
- bonding_eth_dev = &rte_eth_devices[*(uint16_t *)param];
+ bonding_port_id = *(uint16_t *)param;
+ bonding_eth_dev = &rte_eth_devices[bonding_port_id];
if (check_for_bonding_ethdev(bonding_eth_dev))
return rc;
@@ -3058,8 +3060,12 @@ bond_ethdev_lsc_event_callback(uint16_t port_id, enum rte_eth_event_type type,
* using it.
*/
if (internals->user_defined_primary_port &&
- internals->primary_port == port_id)
+ internals->primary_port == port_id) {
bond_ethdev_primary_set(internals, port_id);
+
+ if (internals->notify_member)
+ rte_eth_bond_notify_members(bonding_port_id);
+ }
} else {
if (active_pos == internals->active_member_count)
goto link_update;
@@ -3078,6 +3084,10 @@ bond_ethdev_lsc_event_callback(uint16_t port_id, enum rte_eth_event_type type,
internals->active_members[0]);
else
internals->current_primary_port = internals->primary_port;
+
+ if (internals->notify_member)
+ rte_eth_bond_notify_members(bonding_port_id);
+
mac_address_members_update(bonding_eth_dev);
bond_ethdev_promiscuous_update(bonding_eth_dev);
bond_ethdev_allmulticast_update(bonding_eth_dev);
@@ -3376,6 +3386,7 @@ dump_basic(const struct rte_eth_dev *dev, FILE *f)
struct bond_dev_private instant_priv;
const struct bond_dev_private *internals = &instant_priv;
int mode, i;
+ bool notify_member;
/* Obtain a instance of dev_private to prevent data from being modified. */
memcpy(&instant_priv, dev->data->dev_private, sizeof(struct bond_dev_private));
@@ -3445,6 +3456,13 @@ dump_basic(const struct rte_eth_dev *dev, FILE *f)
fprintf(f, "\tUser Defined Primary: [%u]\n", internals->primary_port);
if (internals->member_count > 0)
fprintf(f, "\tCurrent Primary: [%u]\n", internals->current_primary_port);
+
+ if (rte_eth_bond_notify_member_flag_get(internals->port_id, ¬ify_member) == 0)
+ fprintf(f, "\tNotify Member Ports Flag: %s\n",
+ notify_member ? "enable" : "disable");
+ else
+ fprintf(f, "\tFailed to get notify member ports flag for bonding port %d\n",
+ internals->port_id);
}
static void
@@ -3997,8 +4015,12 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
* if no kvlist, it means that this bonding device has been created
* through the bonding api.
*/
- if (!kvlist || internals->kvargs_processing_is_done)
+ if (!kvlist || internals->kvargs_processing_is_done) {
+ if (internals->notify_member && rte_eth_bond_notify_members(port_id) != 0)
+ RTE_BOND_LOG(ERR, "Notify member ports failed");
+
return 0;
+ }
internals->kvargs_processing_is_done = true;
@@ -4236,6 +4258,10 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
return -1;
}
}
+
+ if (internals->notify_member && rte_eth_bond_notify_members(port_id) != 0)
+ RTE_BOND_LOG(ERR, "Notify member ports failed");
+
return 0;
}
@@ -35,4 +35,7 @@ EXPERIMENTAL {
rte_eth_bond_member_add;
rte_eth_bond_member_remove;
rte_eth_bond_members_get;
+ rte_eth_bond_notify_member_flag_get;
+ rte_eth_bond_notify_member_flag_set;
+ rte_eth_bond_notify_members;
};
@@ -1216,6 +1216,21 @@ typedef int (*eth_count_aggr_ports_t)(struct rte_eth_dev *dev);
typedef int (*eth_map_aggr_tx_affinity_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,
uint8_t affinity);
+/**
+ * @internal
+ * Bonding port notifies the member ports.
+ *
+ * @param dev
+ * Member port (ethdev) handle.
+ * @param bonding_dev
+ * Bonding port (ethdev) handle.
+ *
+ * @return
+ * Negative on error, 0 on success.
+ */
+typedef int (*eth_bond_notify_member)(struct rte_eth_dev *dev,
+ struct rte_eth_dev *bonding_dev);
+
/**
* @internal A structure containing the functions exported by an Ethernet driver.
*/
@@ -1455,6 +1470,9 @@ struct eth_dev_ops {
eth_count_aggr_ports_t count_aggr_ports;
/** Map a Tx queue with an aggregated port of the DPDK port */
eth_map_aggr_tx_affinity_t map_aggr_tx_affinity;
+
+ /** Notify the member port of bonding port information */
+ eth_bond_notify_member bond_notify_member;
};
/**