Commit 5dfe0710 authored by Yangbo Lu's avatar Yangbo Lu Committed by Benjamin Cabé
Browse files

samples: net: dsa: rework for flexibility and extensibility



Current DSA sample is initially for ip_k66f board with a switch PHY,
while it is expected as a common DSA sample for all DSA devices.

This patch does not change any function. It only reworks the sample
with new added CONFIG_NET_SAMPLE_DSA_LLDP for ip_k66f with 3 LAN
ports.
Ideally this should be common for all DSA devices, but for now, ip_k66f
is the only platform supporting it.
As there will be more DSA functions supported, better to allow each
function enablement via option to suit hardware or device driver support
status.

Also improved dsa_ll_addr_switch_cb return value with enum value instead
of plain value.

Signed-off-by: default avatarYangbo Lu <yangbo.lu@nxp.com>
parent 3cc12b5d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(dsa)

target_sources(app PRIVATE src/main.c src/dsa_lldp.c)
target_sources(app PRIVATE src/main.c)
target_sources_ifdef(CONFIG_NET_SAMPLE_DSA_LLDP app PRIVATE src/dsa_lldp.c)
+25 −0
Original line number Diff line number Diff line
# Private config options for DSA

# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0

mainmenu "DSA sample application"

if NET_DSA

config NET_SAMPLE_DSA_MAX_SLAVE_PORTS
	int "DSA slave ports maximum number"
	range 2 10
	default 3
	help
	  DSA slave ports maximum number.

config NET_SAMPLE_DSA_LLDP
	bool "DSA LLDP example"
	default y
	help
	  Enable DSA LLDP example.

endif

source "Kconfig.zephyr"
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2020 DENX Software Engineering GmbH
 * Copyright 2024 NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __DSA_SAMPLE__
#define __DSA_SAMPLE__

#include <zephyr/net/dsa.h>
#include <zephyr/net/ethernet.h>

extern struct ud user_data;

/* User data for the interface callback */
struct ud {
	struct net_if *lan[CONFIG_NET_SAMPLE_DSA_MAX_SLAVE_PORTS];
	struct net_if *master;
};

#endif
+73 −7
Original line number Diff line number Diff line
@@ -18,16 +18,82 @@
#include <errno.h>

#include <zephyr/logging/log.h>
#include "main.h"

/* Loglevel of dsa_lldp function */
LOG_MODULE_DECLARE(net_dsa_lldp_sample, CONFIG_NET_DSA_LOG_LEVEL);
LOG_MODULE_DECLARE(net_dsa_sample, CONFIG_NET_DSA_LOG_LEVEL);

#include "dsa_lldp.h"

#define LLDP_SYSTEM_NAME_SIZE    24
#define LLDP_ETHER_TYPE          0x88CC
#define LLDP_INPUT_DATA_BUF_SIZE 512
#define DSA_BUF_SIZ              128
int dsa_lldp_send(struct net_if *iface, struct instance_data *pd, uint16_t lan, int src_port,

static const uint8_t eth_filter_l2_addr_base[][6] = {
	/* MAC address of other device - for filtering testing */
	{0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}};

enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface, struct net_pkt *pkt)
{
	struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
	struct net_linkaddr lladst;

	net_pkt_cursor_init(pkt);
	lladst.len = sizeof(hdr->dst.addr);
	lladst.addr = &hdr->dst.addr[0];

	/*
	 * Pass packet to lan1..3 when matching one from
	 * check_ll_ether_addr table
	 */
	if (check_ll_ether_addr(lladst.addr, &eth_filter_l2_addr_base[0][0])) {
		return NET_CONTINUE;
	}

	return NET_OK;
}

int start_slave_port_packet_socket(struct net_if *iface, struct instance_data *pd)
{
	struct sockaddr_ll dst;
	int ret;

	pd->sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if (pd->sock < 0) {
		LOG_ERR("Failed to create RAW socket : %d", errno);
		return -errno;
	}

	dst.sll_ifindex = net_if_get_by_iface(iface);
	dst.sll_family = AF_PACKET;

	ret = bind(pd->sock, (const struct sockaddr *)&dst, sizeof(struct sockaddr_ll));
	if (ret < 0) {
		LOG_ERR("Failed to bind packet socket : %d", errno);
		return -errno;
	}

	return 0;
}

void dsa_lldp(struct ud *user_data)
{
	uint8_t tbl_buf[8];

	/*
	 * Set static table to forward LLDP protocol packets
	 * to master port.
	 */
	dsa_switch_set_mac_table_entry(user_data->lan[0], &eth_filter_l2_addr_base[0][0], BIT(4), 0,
				       0);
	dsa_switch_get_mac_table_entry(user_data->lan[0], tbl_buf, 0);

	LOG_INF("DSA static MAC address table entry [%d]:", 0);
	LOG_INF("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", tbl_buf[7], tbl_buf[6], tbl_buf[5],
		tbl_buf[4], tbl_buf[3], tbl_buf[2], tbl_buf[1], tbl_buf[0]);
}

static int dsa_lldp_send(struct net_if *iface, struct instance_data *pd, uint16_t lan, int src_port,
			 int origin_port, int cmd, struct eth_addr *origin_addr)
{
	int ret, len;
@@ -91,7 +157,7 @@ int dsa_lldp_send(struct net_if *iface, struct instance_data *pd, uint16_t lan,
	return 0;
}

void dsa_lldp_print_info(uint8_t *lldp_p, uint8_t lanid)
static void dsa_lldp_print_info(uint8_t *lldp_p, uint8_t lanid)
{
	uint16_t tl, length;
	uint8_t type, subtype;
@@ -145,8 +211,8 @@ void dsa_lldp_print_info(uint8_t *lldp_p, uint8_t lanid)
	} while (1);
}

int dsa_lldp_recv(struct net_if *iface, struct instance_data *pd, uint16_t *lan, int *origin_port,
		  struct eth_addr *origin_addr)
static int dsa_lldp_recv(struct net_if *iface, struct instance_data *pd, uint16_t *lan,
			 int *origin_port, struct eth_addr *origin_addr)
{
	struct ethernet_context *ctx = net_if_l2_data(iface);
	struct net_eth_hdr *eth_hdr = (struct net_eth_hdr *)pd->recv_buffer;
+98 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2020 DENX Software Engineering GmbH
 * Copyright 2024 NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __DSA_SAMPLE__
#define __DSA_SAMPLE__
#ifndef __DSA_SAMPLE_LLDP__
#define __DSA_SAMPLE_LLDP__

#include <zephyr/kernel.h>
#include <errno.h>

#include <zephyr/net/net_core.h>
#include <zephyr/net/net_l2.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/ethernet.h>
#include "dsa.h"

#define MCAST_DEST_MAC0 0x01
#define MCAST_DEST_MAC1 0x80
@@ -27,8 +21,6 @@
#define ETH_ALEN         6
#define PACKET_LEN       128

extern struct ud user_data_ifaces;

struct eth_addr {
	uint8_t addr[ETH_ALEN]; /* origin hardware address */
};
@@ -39,16 +31,10 @@ struct instance_data {
	char recv_buffer[RECV_BUFFER_SIZE];
};

/* User data for the interface callback */
struct ud {
	struct net_if *lan[3];
	struct net_if *master;
};

static inline bool check_ll_ether_addr(const uint8_t *a, const uint8_t *b)
{
	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) |
		(a[3] ^ b[3]) | (a[4] ^ b[4]) | (a[5] ^ b[5])) == 0;
	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) | (a[3] ^ b[3]) | (a[4] ^ b[4]) |
		(a[5] ^ b[5])) == 0;
}

static inline void dsa_buf_write_be16(uint16_t tl, uint8_t **p)
@@ -60,11 +46,11 @@ static inline void dsa_buf_write_be16(uint16_t tl, uint8_t **p)
	(*p)++;
}

int start_slave_port_packet_socket(struct net_if *iface,
				   struct instance_data *pd);
int start_slave_port_packet_socket(struct net_if *iface, struct instance_data *pd);

enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface, struct net_pkt *pkt);

enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface,
				       struct net_pkt *pkt);
void dsa_lldp(struct ud *user_data);

#define CMD_DISCOVER           0
#define CMD_ACK                1
@@ -74,8 +60,7 @@ enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface,

#define DSA_THREAD(ID, FN_RECV, FN_SEND)                                                           \
	static void dsa_thread_##ID(void *t1, void *t2, void *t3);                                 \
	K_THREAD_DEFINE(dsa_tid_##ID, DSA_STACK_SIZE,                          \
		dsa_thread_##ID, NULL, NULL, NULL,                             \
	K_THREAD_DEFINE(dsa_tid_##ID, DSA_STACK_SIZE, dsa_thread_##ID, NULL, NULL, NULL,           \
			DSA_PRIORITY, 0, DSA_THREAD_START_DELAY);                                  \
                                                                                                   \
	void dsa_thread_##ID(void *t1, void *t2, void *t3)                                         \
@@ -86,33 +71,28 @@ enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface,
		struct instance_data data;                                                         \
		struct net_if *iface;                                                              \
                                                                                                   \
		iface = user_data_ifaces.lan[ID-1];                            \
		iface = user_data.lan[ID - 1];                                                     \
                                                                                                   \
		data.if_name = "lan" #ID;                                                          \
		ret = start_slave_port_packet_socket(iface, &data);                                \
		if (ret < 0) {                                                                     \
			LOG_ERR("start_slave_port_packet_socket failed %d",    \
				ret);                                          \
			LOG_ERR("start_slave_port_packet_socket failed %d", ret);                  \
			return;                                                                    \
		}                                                                                  \
		dsa_register_recv_callback(iface,                              \
						dsa_ll_addr_switch_cb);        \
		dsa_register_recv_callback(iface, dsa_ll_addr_switch_cb);                          \
                                                                                                   \
		LOG_INF("DSA -> eth/lan"#ID" idx: %d sock: %d",                \
			net_if_get_by_iface(iface), data.sock);                \
		LOG_INF("DSA -> eth/lan" #ID " idx: %d sock: %d", net_if_get_by_iface(iface),      \
			data.sock);                                                                \
		do {                                                                               \
			ret = FN_RECV(iface, &data, &seq,                      \
					&origin_port, &origin_addr);           \
			ret = FN_RECV(iface, &data, &seq, &origin_port, &origin_addr);             \
			if (ret) {                                                                 \
				break;                                                             \
			}                                                                          \
			ret = FN_SEND(iface, &data,                            \
					seq, 0, origin_port, CMD_ACK,          \
					&origin_addr);                         \
			ret = FN_SEND(iface, &data, seq, 0, origin_port, CMD_ACK, &origin_addr);   \
			if (ret) {                                                                 \
				break;                                                             \
			}                                                                          \
		} while (true);                                                                    \
	}

#endif /* __DSA_SAMPLE__ */
#endif /* __DSA_SAMPLE_LLDP__ */
Loading