1 /*
2  * Copyright (c) 2021 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define NET_LOG_LEVEL CONFIG_NET_ETHERNET_BRIDGE_LOG_LEVEL
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
11 
12 #include <zephyr/types.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <zephyr/sys/printk.h>
18 
19 #include <zephyr/ztest.h>
20 
21 #include <zephyr/net/net_if.h>
22 #include <zephyr/net/ethernet.h>
23 #include <zephyr/net/ethernet_bridge.h>
24 
25 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
26 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
27 #else
28 #define DBG(fmt, ...)
29 #endif
30 
31 struct eth_fake_context {
32 	struct net_if *iface;
33 	struct net_pkt *sent_pkt;
34 	uint8_t mac_address[6];
35 	bool promisc_mode;
36 };
37 
eth_fake_iface_init(struct net_if * iface)38 static void eth_fake_iface_init(struct net_if *iface)
39 {
40 	const struct device *dev = net_if_get_device(iface);
41 	struct eth_fake_context *ctx = dev->data;
42 
43 	ctx->iface = iface;
44 
45 	ctx->mac_address[0] = 0xc2;
46 	ctx->mac_address[1] = 0xaa;
47 	ctx->mac_address[2] = 0xbb;
48 	ctx->mac_address[3] = 0xcc;
49 	ctx->mac_address[4] = 0xdd;
50 	ctx->mac_address[5] = 0xee;
51 
52 	net_if_set_link_addr(iface, ctx->mac_address,
53 			     sizeof(ctx->mac_address),
54 			     NET_LINK_ETHERNET);
55 
56 	ethernet_init(iface);
57 }
58 
eth_fake_send(const struct device * dev,struct net_pkt * pkt)59 static int eth_fake_send(const struct device *dev,
60 			 struct net_pkt *pkt)
61 {
62 	struct eth_fake_context *ctx = dev->data;
63 	struct net_eth_hdr *eth_hdr = NET_ETH_HDR(pkt);
64 
65 	/*
66 	 * Ignore packets we don't care about for this test, like
67 	 * the IP autoconfig related ones, etc.
68 	 */
69 	if (eth_hdr->type != htons(NET_ETH_PTYPE_ALL)) {
70 		DBG("Fake send ignoring pkt %p\n", pkt);
71 		return 0;
72 	}
73 
74 	if (ctx->sent_pkt != NULL) {
75 		DBG("Fake send found pkt %p while sending %p\n",
76 		    ctx->sent_pkt, pkt);
77 		return -EBUSY;
78 	}
79 	ctx->sent_pkt = net_pkt_shallow_clone(pkt, K_NO_WAIT);
80 	if (ctx->sent_pkt == NULL) {
81 		DBG("Fake send out of mem while sending pkt %p\n", pkt);
82 		return -ENOMEM;
83 	}
84 
85 	DBG("Fake send pkt %p kept locally as %p\n", pkt, ctx->sent_pkt);
86 	return 0;
87 }
88 
eth_fake_get_capabilities(const struct device * dev)89 static enum ethernet_hw_caps eth_fake_get_capabilities(const struct device *dev)
90 {
91 	return ETHERNET_PROMISC_MODE;
92 }
93 
eth_fake_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)94 static int eth_fake_set_config(const struct device *dev,
95 			       enum ethernet_config_type type,
96 			       const struct ethernet_config *config)
97 {
98 	struct eth_fake_context *ctx = dev->data;
99 
100 	switch (type) {
101 	case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
102 		if (config->promisc_mode == ctx->promisc_mode) {
103 			return -EALREADY;
104 		}
105 
106 		ctx->promisc_mode = config->promisc_mode;
107 
108 		break;
109 
110 	default:
111 		return -EINVAL;
112 	}
113 
114 	return 0;
115 }
116 
117 static const struct ethernet_api eth_fake_api_funcs = {
118 	.iface_api.init = eth_fake_iface_init,
119 	.get_capabilities = eth_fake_get_capabilities,
120 	.set_config = eth_fake_set_config,
121 	.send = eth_fake_send,
122 };
123 
eth_fake_init(const struct device * dev)124 static int eth_fake_init(const struct device *dev)
125 {
126 	struct eth_fake_context *ctx = dev->data;
127 
128 	ctx->promisc_mode = false;
129 
130 	return 0;
131 }
132 
133 static struct eth_fake_context eth_fake_data[3];
134 
135 ETH_NET_DEVICE_INIT(eth_fake0, "eth_fake0",
136 		    eth_fake_init, NULL,
137 		    &eth_fake_data[0], NULL, CONFIG_ETH_INIT_PRIORITY,
138 		    &eth_fake_api_funcs, NET_ETH_MTU);
139 
140 ETH_NET_DEVICE_INIT(eth_fake1, "eth_fake1",
141 		    eth_fake_init, NULL,
142 		    &eth_fake_data[1], NULL, CONFIG_ETH_INIT_PRIORITY,
143 		    &eth_fake_api_funcs, NET_ETH_MTU);
144 
145 ETH_NET_DEVICE_INIT(eth_fake2, "eth_fake2",
146 		    eth_fake_init, NULL,
147 		    &eth_fake_data[2], NULL, CONFIG_ETH_INIT_PRIORITY,
148 		    &eth_fake_api_funcs, NET_ETH_MTU);
149 
150 static struct net_if *fake_iface[3];
151 
iface_cb(struct net_if * iface,void * user_data)152 static void iface_cb(struct net_if *iface, void *user_data)
153 {
154 	static int if_count;
155 
156 	if (if_count >= ARRAY_SIZE(fake_iface)) {
157 		return;
158 	}
159 
160 	DBG("Interface %p [%d]\n", iface, net_if_get_by_iface(iface));
161 
162 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
163 		const struct ethernet_api *api =
164 			net_if_get_device(iface)->api;
165 
166 		/*
167 		 * We want to only use struct net_if devices defined in
168 		 * this test as board on which it is run can have its
169 		 * own set of interfaces.
170 		 */
171 		if (api->get_capabilities ==
172 		    eth_fake_api_funcs.get_capabilities) {
173 			fake_iface[if_count++] = iface;
174 		}
175 	}
176 }
177 
178 static int orig_rx_num_blocks;
179 static int orig_tx_num_blocks;
180 
get_free_packet_count(void)181 static void get_free_packet_count(void)
182 {
183 	struct k_mem_slab *rx, *tx;
184 
185 	net_pkt_get_info(&rx, &tx, NULL, NULL);
186 	orig_rx_num_blocks = rx->info.num_blocks;
187 	orig_tx_num_blocks = tx->info.num_blocks;
188 }
189 
check_free_packet_count(void)190 static void check_free_packet_count(void)
191 {
192 	struct k_mem_slab *rx, *tx;
193 
194 	net_pkt_get_info(&rx, &tx, NULL, NULL);
195 	zassert_equal(rx->info.num_blocks, orig_rx_num_blocks, "");
196 	zassert_equal(tx->info.num_blocks, orig_tx_num_blocks, "");
197 }
198 
test_iface_setup(void)199 static void test_iface_setup(void)
200 {
201 	net_if_foreach(iface_cb, NULL);
202 
203 	zassert_not_null(fake_iface[0], "");
204 	zassert_not_null(fake_iface[1], "");
205 	zassert_not_null(fake_iface[2], "");
206 
207 	DBG("Interfaces: [%d] iface0 %p, [%d] iface1 %p, [%d] iface2 %p\n",
208 	    net_if_get_by_iface(fake_iface[0]), fake_iface[0],
209 	    net_if_get_by_iface(fake_iface[1]), fake_iface[1],
210 	    net_if_get_by_iface(fake_iface[2]), fake_iface[2]);
211 
212 	net_if_up(fake_iface[0]);
213 	net_if_up(fake_iface[1]);
214 	net_if_up(fake_iface[2]);
215 
216 	/* Remember the initial number of free packets in the pool. */
217 	get_free_packet_count();
218 }
219 
220 /*
221  * Simulate a packet reception from the outside world
222  */
_recv_data(struct net_if * iface)223 static void _recv_data(struct net_if *iface)
224 {
225 	struct net_pkt *pkt;
226 	struct net_eth_hdr eth_hdr;
227 	static uint8_t data[] = { 't', 'e', 's', 't', '\0' };
228 	int ret;
229 
230 	pkt = net_pkt_rx_alloc_with_buffer(iface, sizeof(eth_hdr) + sizeof(data),
231 					   AF_UNSPEC, 0, K_FOREVER);
232 	zassert_not_null(pkt, "");
233 
234 	/*
235 	 * The source and destination MAC addresses are completely arbitrary
236 	 * except for the U/L and I/G bits. However, the index of the faked
237 	 * incoming interface is mixed in as well to create some variation,
238 	 * and to help with validation on the transmit side.
239 	 */
240 
241 	eth_hdr.dst.addr[0] = 0xb2;
242 	eth_hdr.dst.addr[1] = 0x11;
243 	eth_hdr.dst.addr[2] = 0x22;
244 	eth_hdr.dst.addr[3] = 0x33;
245 	eth_hdr.dst.addr[4] = net_if_get_by_iface(iface);
246 	eth_hdr.dst.addr[5] = 0x55;
247 
248 	eth_hdr.src.addr[0] = 0xa2;
249 	eth_hdr.src.addr[1] = 0x11;
250 	eth_hdr.src.addr[2] = 0x22;
251 	eth_hdr.src.addr[3] = net_if_get_by_iface(iface);
252 	eth_hdr.src.addr[4] = 0x77;
253 	eth_hdr.src.addr[5] = 0x88;
254 
255 	eth_hdr.type = htons(NET_ETH_PTYPE_ALL);
256 
257 	ret = net_pkt_write(pkt, &eth_hdr, sizeof(eth_hdr));
258 	zassert_equal(ret, 0, "");
259 
260 	ret = net_pkt_write(pkt, data, sizeof(data));
261 	zassert_equal(ret, 0, "");
262 
263 	DBG("Fake recv pkt %p\n", pkt);
264 	ret = net_recv_data(iface, pkt);
265 	zassert_equal(ret, 0, "");
266 }
267 
test_recv_before_bridging(void)268 static void test_recv_before_bridging(void)
269 {
270 	/* fake some packet reception */
271 	_recv_data(fake_iface[0]);
272 	_recv_data(fake_iface[1]);
273 	_recv_data(fake_iface[2]);
274 
275 	/* give time to the processing threads to run */
276 	k_sleep(K_MSEC(100));
277 
278 	/* nothing should have been transmitted at this point */
279 	zassert_is_null(eth_fake_data[0].sent_pkt, "");
280 	zassert_is_null(eth_fake_data[1].sent_pkt, "");
281 	zassert_is_null(eth_fake_data[2].sent_pkt, "");
282 
283 	/* and everything already dropped. */
284 	check_free_packet_count();
285 }
286 
287 static ETH_BRIDGE_INIT(test_bridge);
288 
test_setup_bridge(void)289 static void test_setup_bridge(void)
290 {
291 	int ret;
292 
293 	/* add our interfaces to the bridge */
294 	ret = eth_bridge_iface_add(&test_bridge, fake_iface[0]);
295 	zassert_equal(ret, 0, "");
296 	ret = eth_bridge_iface_add(&test_bridge, fake_iface[1]);
297 	zassert_equal(ret, 0, "");
298 	ret = eth_bridge_iface_add(&test_bridge, fake_iface[2]);
299 	zassert_equal(ret, 0, "");
300 
301 	/* enable tx for them except fake_iface[1] */
302 	ret = eth_bridge_iface_allow_tx(fake_iface[0], true);
303 	zassert_equal(ret, 0, "");
304 	ret = eth_bridge_iface_allow_tx(fake_iface[2], true);
305 	zassert_equal(ret, 0, "");
306 }
307 
test_recv_with_bridge(void)308 static void test_recv_with_bridge(void)
309 {
310 	int i, j;
311 
312 	for (i = 0; i < 3; i++) {
313 		int src_if_idx = net_if_get_by_iface(fake_iface[i]);
314 
315 		/* fake reception of packets */
316 		_recv_data(fake_iface[i]);
317 
318 		/* give time to the processing threads to run */
319 		k_sleep(K_MSEC(100));
320 
321 		/* nothing should have been transmitted on fake_iface[1] */
322 		zassert_is_null(eth_fake_data[1].sent_pkt, "");
323 
324 		/*
325 		 * fake_iface[0] and fake_iface[2] should have sent the packet
326 		 * but only if it didn't come from them.
327 		 * We skip fake_iface[1] handled above.
328 		 */
329 		for (j = 0; j < 3; j += 2) {
330 			struct net_pkt *pkt = eth_fake_data[j].sent_pkt;
331 
332 			if (eth_fake_data[j].iface == fake_iface[i]) {
333 				zassert_is_null(pkt, "");
334 				continue;
335 			}
336 
337 			eth_fake_data[j].sent_pkt = NULL;
338 			zassert_not_null(pkt, "");
339 
340 			/* make sure nothing messed up our ethernet header */
341 			struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
342 
343 			zassert_equal(hdr->dst.addr[0], 0xb2, "");
344 			zassert_equal(hdr->src.addr[0], 0xa2, "");
345 			zassert_equal(hdr->dst.addr[4], src_if_idx, "");
346 			zassert_equal(hdr->src.addr[3], src_if_idx, "");
347 
348 			net_pkt_unref(pkt);
349 		}
350 	}
351 
352 	check_free_packet_count();
353 }
354 
test_recv_after_bridging(void)355 static void test_recv_after_bridging(void)
356 {
357 	int ret;
358 
359 	/* remove our interfaces from the bridge */
360 	ret = eth_bridge_iface_remove(&test_bridge, fake_iface[0]);
361 	zassert_equal(ret, 0, "");
362 	ret = eth_bridge_iface_remove(&test_bridge, fake_iface[1]);
363 	zassert_equal(ret, 0, "");
364 	ret = eth_bridge_iface_remove(&test_bridge, fake_iface[2]);
365 	zassert_equal(ret, 0, "");
366 
367 	/* things should have returned to the pre-bridging state */
368 	test_recv_before_bridging();
369 }
370 
ZTEST(net_eth_bridge,test_net_eth_bridge)371 ZTEST(net_eth_bridge, test_net_eth_bridge)
372 {
373 	test_iface_setup();
374 	test_recv_before_bridging();
375 	test_setup_bridge();
376 	test_recv_with_bridge();
377 	test_recv_after_bridging();
378 }
379 
380 ZTEST_SUITE(net_eth_bridge, NULL, NULL, NULL, NULL, NULL);
381