xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/netif/bridgeif_fdb.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /**
2*10465441SEvalZero  * @file
3*10465441SEvalZero  * lwIP netif implementing an FDB for IEEE 802.1D MAC Bridge
4*10465441SEvalZero  */
5*10465441SEvalZero 
6*10465441SEvalZero /*
7*10465441SEvalZero  * Copyright (c) 2017 Simon Goldschmidt.
8*10465441SEvalZero  * All rights reserved.
9*10465441SEvalZero  *
10*10465441SEvalZero  * Redistribution and use in source and binary forms, with or without modification,
11*10465441SEvalZero  * are permitted provided that the following conditions are met:
12*10465441SEvalZero  *
13*10465441SEvalZero  * 1. Redistributions of source code must retain the above copyright notice,
14*10465441SEvalZero  *    this list of conditions and the following disclaimer.
15*10465441SEvalZero  * 2. Redistributions in binary form must reproduce the above copyright notice,
16*10465441SEvalZero  *    this list of conditions and the following disclaimer in the documentation
17*10465441SEvalZero  *    and/or other materials provided with the distribution.
18*10465441SEvalZero  * 3. The name of the author may not be used to endorse or promote products
19*10465441SEvalZero  *    derived from this software without specific prior written permission.
20*10465441SEvalZero  *
21*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22*10465441SEvalZero  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23*10465441SEvalZero  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24*10465441SEvalZero  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25*10465441SEvalZero  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26*10465441SEvalZero  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*10465441SEvalZero  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*10465441SEvalZero  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29*10465441SEvalZero  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30*10465441SEvalZero  * OF SUCH DAMAGE.
31*10465441SEvalZero  *
32*10465441SEvalZero  * This file is part of the lwIP TCP/IP stack.
33*10465441SEvalZero  *
34*10465441SEvalZero  * Author: Simon Goldschmidt <[email protected]>
35*10465441SEvalZero  *
36*10465441SEvalZero  */
37*10465441SEvalZero 
38*10465441SEvalZero /**
39*10465441SEvalZero  * @defgroup bridgeif_fdb FDB example code
40*10465441SEvalZero  * @ingroup bridgeif
41*10465441SEvalZero  * This file implements an example for an FDB (Forwarding DataBase)
42*10465441SEvalZero  */
43*10465441SEvalZero 
44*10465441SEvalZero #include "netif/bridgeif.h"
45*10465441SEvalZero #include "lwip/sys.h"
46*10465441SEvalZero #include "lwip/mem.h"
47*10465441SEvalZero #include "lwip/timeouts.h"
48*10465441SEvalZero #include <string.h>
49*10465441SEvalZero 
50*10465441SEvalZero #define BRIDGEIF_AGE_TIMER_MS 1000
51*10465441SEvalZero 
52*10465441SEvalZero #define BR_FDB_TIMEOUT_SEC  (60*5) /* 5 minutes FDB timeout */
53*10465441SEvalZero 
54*10465441SEvalZero typedef struct bridgeif_dfdb_entry_s {
55*10465441SEvalZero   u8_t used;
56*10465441SEvalZero   u8_t port;
57*10465441SEvalZero   u32_t ts;
58*10465441SEvalZero   struct eth_addr addr;
59*10465441SEvalZero } bridgeif_dfdb_entry_t;
60*10465441SEvalZero 
61*10465441SEvalZero typedef struct bridgeif_dfdb_s {
62*10465441SEvalZero   u16_t max_fdb_entries;
63*10465441SEvalZero   bridgeif_dfdb_entry_t *fdb;
64*10465441SEvalZero } bridgeif_dfdb_t;
65*10465441SEvalZero 
66*10465441SEvalZero /**
67*10465441SEvalZero  * @ingroup bridgeif_fdb
68*10465441SEvalZero  * A real simple and slow implementation of an auto-learning forwarding database that
69*10465441SEvalZero  * remembers known src mac addresses to know which port to send frames destined for that
70*10465441SEvalZero  * mac address.
71*10465441SEvalZero  *
72*10465441SEvalZero  * ATTENTION: This is meant as an example only, in real-world use, you should
73*10465441SEvalZero  * provide a better implementation :-)
74*10465441SEvalZero  */
75*10465441SEvalZero void
bridgeif_fdb_update_src(void * fdb_ptr,struct eth_addr * src_addr,u8_t port_idx)76*10465441SEvalZero bridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx)
77*10465441SEvalZero {
78*10465441SEvalZero   int i;
79*10465441SEvalZero   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
80*10465441SEvalZero   BRIDGEIF_DECL_PROTECT(lev);
81*10465441SEvalZero   BRIDGEIF_READ_PROTECT(lev);
82*10465441SEvalZero   for (i = 0; i < fdb->max_fdb_entries; i++) {
83*10465441SEvalZero     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
84*10465441SEvalZero     if (e->used && e->ts) {
85*10465441SEvalZero       if (!memcmp(&e->addr, src_addr, sizeof(struct eth_addr))) {
86*10465441SEvalZero         LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: update src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
87*10465441SEvalZero                                          src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
88*10465441SEvalZero                                          port_idx, i));
89*10465441SEvalZero         BRIDGEIF_WRITE_PROTECT(lev);
90*10465441SEvalZero         e->ts = BR_FDB_TIMEOUT_SEC;
91*10465441SEvalZero         e->port = port_idx;
92*10465441SEvalZero         BRIDGEIF_WRITE_UNPROTECT(lev);
93*10465441SEvalZero         BRIDGEIF_READ_UNPROTECT(lev);
94*10465441SEvalZero         return;
95*10465441SEvalZero       }
96*10465441SEvalZero     }
97*10465441SEvalZero   }
98*10465441SEvalZero   /* not found, allocate new entry from free */
99*10465441SEvalZero   for (i = 0; i < fdb->max_fdb_entries; i++) {
100*10465441SEvalZero     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
101*10465441SEvalZero     if (!e->used || !e->ts) {
102*10465441SEvalZero       BRIDGEIF_WRITE_PROTECT(lev);
103*10465441SEvalZero       /* check again when protected */
104*10465441SEvalZero       if (!e->used || !e->ts) {
105*10465441SEvalZero         LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: create src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
106*10465441SEvalZero                                          src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
107*10465441SEvalZero                                          port_idx, i));
108*10465441SEvalZero         memcpy(&e->addr, src_addr, sizeof(struct eth_addr));
109*10465441SEvalZero         e->ts = BR_FDB_TIMEOUT_SEC;
110*10465441SEvalZero         e->port = port_idx;
111*10465441SEvalZero         e->used = 1;
112*10465441SEvalZero         BRIDGEIF_WRITE_UNPROTECT(lev);
113*10465441SEvalZero         BRIDGEIF_READ_UNPROTECT(lev);
114*10465441SEvalZero         return;
115*10465441SEvalZero       }
116*10465441SEvalZero       BRIDGEIF_WRITE_UNPROTECT(lev);
117*10465441SEvalZero     }
118*10465441SEvalZero   }
119*10465441SEvalZero   BRIDGEIF_READ_UNPROTECT(lev);
120*10465441SEvalZero   /* not found, no free entry -> flood */
121*10465441SEvalZero }
122*10465441SEvalZero 
123*10465441SEvalZero /**
124*10465441SEvalZero  * @ingroup bridgeif_fdb
125*10465441SEvalZero  * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown
126*10465441SEvalZero  */
127*10465441SEvalZero bridgeif_portmask_t
bridgeif_fdb_get_dst_ports(void * fdb_ptr,struct eth_addr * dst_addr)128*10465441SEvalZero bridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr)
129*10465441SEvalZero {
130*10465441SEvalZero   int i;
131*10465441SEvalZero   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
132*10465441SEvalZero   BRIDGEIF_DECL_PROTECT(lev);
133*10465441SEvalZero   BRIDGEIF_READ_PROTECT(lev);
134*10465441SEvalZero   for (i = 0; i < fdb->max_fdb_entries; i++) {
135*10465441SEvalZero     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
136*10465441SEvalZero     if (e->used && e->ts) {
137*10465441SEvalZero       if (!memcmp(&e->addr, dst_addr, sizeof(struct eth_addr))) {
138*10465441SEvalZero         bridgeif_portmask_t ret = (bridgeif_portmask_t)(1 << e->port);
139*10465441SEvalZero         BRIDGEIF_READ_UNPROTECT(lev);
140*10465441SEvalZero         return ret;
141*10465441SEvalZero       }
142*10465441SEvalZero     }
143*10465441SEvalZero   }
144*10465441SEvalZero   BRIDGEIF_READ_UNPROTECT(lev);
145*10465441SEvalZero   return BR_FLOOD;
146*10465441SEvalZero }
147*10465441SEvalZero 
148*10465441SEvalZero /**
149*10465441SEvalZero  * @ingroup bridgeif_fdb
150*10465441SEvalZero  * Aging implementation of our simple fdb
151*10465441SEvalZero  */
152*10465441SEvalZero static void
bridgeif_fdb_age_one_second(void * fdb_ptr)153*10465441SEvalZero bridgeif_fdb_age_one_second(void *fdb_ptr)
154*10465441SEvalZero {
155*10465441SEvalZero   int i;
156*10465441SEvalZero   bridgeif_dfdb_t *fdb;
157*10465441SEvalZero   BRIDGEIF_DECL_PROTECT(lev);
158*10465441SEvalZero 
159*10465441SEvalZero   fdb = (bridgeif_dfdb_t *)fdb_ptr;
160*10465441SEvalZero   BRIDGEIF_READ_PROTECT(lev);
161*10465441SEvalZero 
162*10465441SEvalZero   for (i = 0; i < fdb->max_fdb_entries; i++) {
163*10465441SEvalZero     bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
164*10465441SEvalZero     if (e->used && e->ts) {
165*10465441SEvalZero       BRIDGEIF_WRITE_PROTECT(lev);
166*10465441SEvalZero       /* check again when protected */
167*10465441SEvalZero       if (e->used && e->ts) {
168*10465441SEvalZero         if (--e->ts == 0) {
169*10465441SEvalZero           e->used = 0;
170*10465441SEvalZero         }
171*10465441SEvalZero       }
172*10465441SEvalZero       BRIDGEIF_WRITE_UNPROTECT(lev);
173*10465441SEvalZero     }
174*10465441SEvalZero   }
175*10465441SEvalZero   BRIDGEIF_READ_UNPROTECT(lev);
176*10465441SEvalZero }
177*10465441SEvalZero 
178*10465441SEvalZero /** Timer callback for fdb aging, called once per second */
179*10465441SEvalZero static void
bridgeif_age_tmr(void * arg)180*10465441SEvalZero bridgeif_age_tmr(void *arg)
181*10465441SEvalZero {
182*10465441SEvalZero   bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)arg;
183*10465441SEvalZero 
184*10465441SEvalZero   LWIP_ASSERT("invalid arg", arg != NULL);
185*10465441SEvalZero 
186*10465441SEvalZero   bridgeif_fdb_age_one_second(fdb);
187*10465441SEvalZero   sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, arg);
188*10465441SEvalZero }
189*10465441SEvalZero 
190*10465441SEvalZero /**
191*10465441SEvalZero  * @ingroup bridgeif_fdb
192*10465441SEvalZero  * Init our simple fdb list
193*10465441SEvalZero  */
194*10465441SEvalZero void *
bridgeif_fdb_init(u16_t max_fdb_entries)195*10465441SEvalZero bridgeif_fdb_init(u16_t max_fdb_entries)
196*10465441SEvalZero {
197*10465441SEvalZero   bridgeif_dfdb_t *fdb;
198*10465441SEvalZero   size_t alloc_len_sizet = sizeof(bridgeif_dfdb_t) + (max_fdb_entries * sizeof(bridgeif_dfdb_entry_t));
199*10465441SEvalZero   mem_size_t alloc_len = (mem_size_t)alloc_len_sizet;
200*10465441SEvalZero   LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet);
201*10465441SEvalZero   LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_fdb_init: allocating %d bytes for private FDB data\n", (int)alloc_len));
202*10465441SEvalZero   fdb = (bridgeif_dfdb_t *)mem_calloc(1, alloc_len);
203*10465441SEvalZero   if (fdb == NULL) {
204*10465441SEvalZero     return NULL;
205*10465441SEvalZero   }
206*10465441SEvalZero   fdb->max_fdb_entries = max_fdb_entries;
207*10465441SEvalZero   fdb->fdb = (bridgeif_dfdb_entry_t *)(fdb + 1);
208*10465441SEvalZero 
209*10465441SEvalZero   sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, fdb);
210*10465441SEvalZero 
211*10465441SEvalZero   return fdb;
212*10465441SEvalZero }
213