drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
Extension
.c
Size
10582 bytes
Lines
412
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mlx5_fib_event_work {
	struct work_struct work;
	struct mlx5_lag *ldev;
	unsigned long event;
	union {
		struct fib_entry_notifier_info fen_info;
		struct fib_nh_notifier_info fnh_info;
	};
};

static struct net_device*
mlx5_lag_get_next_fib_dev(struct mlx5_lag *ldev,
			  struct fib_info *fi,
			  struct net_device *current_dev)
{
	struct net_device *fib_dev;
	int i, ldev_idx, nhs;

	nhs = fib_info_num_path(fi);
	i = 0;
	if (current_dev) {
		for (; i < nhs; i++) {
			fib_dev = fib_info_nh(fi, i)->fib_nh_dev;
			if (fib_dev == current_dev) {
				i++;
				break;
			}
		}
	}
	for (; i < nhs; i++) {
		fib_dev = fib_info_nh(fi, i)->fib_nh_dev;
		ldev_idx = mlx5_lag_dev_get_netdev_idx(ldev, fib_dev);
		if (ldev_idx >= 0)
			return mlx5_lag_pf(ldev, ldev_idx)->netdev;
	}

	return NULL;
}

static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
				     struct fib_entry_notifier_info *fen_info)
{
	int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
	struct net_device *nh_dev0, *nh_dev1;
	struct fib_info *fi = fen_info->fi;
	struct lag_mp *mp = &ldev->lag_mp;
	int i, dev_idx = 0;

	if (idx < 0)
		return;

	/* Handle delete event */
	if (event == FIB_EVENT_ENTRY_DEL) {
		/* stop track */
		if (mp->fib.mfi == fi)
			mp->fib.mfi = NULL;
		return;
	}

	/* Handle multipath entry with lower priority value */
	if (mp->fib.mfi &&
	    (mp->fib.dst != fen_info->dst || mp->fib.dst_len != fen_info->dst_len) &&
	    mp->fib.dst_len <= fen_info->dst_len &&
	    !(mp->fib.dst_len == fen_info->dst_len &&
	      fi->fib_priority < mp->fib.priority)) {
		mlx5_core_dbg(mlx5_lag_pf(ldev, idx)->dev,
			      "Multipath entry with lower priority was rejected\n");
		return;
	}

	nh_dev0 = mlx5_lag_get_next_fib_dev(ldev, fi, NULL);
	nh_dev1 = mlx5_lag_get_next_fib_dev(ldev, fi, nh_dev0);

	/* Handle add/replace event */
	if (!nh_dev0) {
		if (mp->fib.dst == fen_info->dst && mp->fib.dst_len == fen_info->dst_len)
			mp->fib.mfi = NULL;
		return;
	}

	if (nh_dev0 == nh_dev1) {
		mlx5_core_warn(mlx5_lag_pf(ldev, idx)->dev,
			       "Multipath offload doesn't support routes with multiple nexthops of the same device");
		return;
	}

	if (!nh_dev1) {
		if (__mlx5_lag_is_active(ldev)) {
			mlx5_ldev_for_each(i, 0, ldev) {
				dev_idx++;

Annotation

Implementation Notes