xref: /third_party/lwip/src/netif/bridgeif_fdb.c (revision 195972f6)
1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * lwIP netif implementing an FDB for IEEE 802.1D MAC Bridge
4195972f6Sopenharmony_ci */
5195972f6Sopenharmony_ci
6195972f6Sopenharmony_ci/*
7195972f6Sopenharmony_ci * Copyright (c) 2017 Simon Goldschmidt.
8195972f6Sopenharmony_ci * All rights reserved.
9195972f6Sopenharmony_ci *
10195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
11195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
12195972f6Sopenharmony_ci *
13195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
14195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
15195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
16195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
17195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
18195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
19195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
20195972f6Sopenharmony_ci *
21195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30195972f6Sopenharmony_ci * OF SUCH DAMAGE.
31195972f6Sopenharmony_ci *
32195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack.
33195972f6Sopenharmony_ci *
34195972f6Sopenharmony_ci * Author: Simon Goldschmidt <goldsimon@gmx.de>
35195972f6Sopenharmony_ci *
36195972f6Sopenharmony_ci */
37195972f6Sopenharmony_ci
38195972f6Sopenharmony_ci/**
39195972f6Sopenharmony_ci * @defgroup bridgeif_fdb FDB example code
40195972f6Sopenharmony_ci * @ingroup bridgeif
41195972f6Sopenharmony_ci * This file implements an example for an FDB (Forwarding DataBase)
42195972f6Sopenharmony_ci */
43195972f6Sopenharmony_ci
44195972f6Sopenharmony_ci#include "netif/bridgeif.h"
45195972f6Sopenharmony_ci#include "lwip/sys.h"
46195972f6Sopenharmony_ci#include "lwip/mem.h"
47195972f6Sopenharmony_ci#include "lwip/timeouts.h"
48195972f6Sopenharmony_ci#include <string.h>
49195972f6Sopenharmony_ci
50195972f6Sopenharmony_ci#define BRIDGEIF_AGE_TIMER_MS 1000
51195972f6Sopenharmony_ci
52195972f6Sopenharmony_ci#define BR_FDB_TIMEOUT_SEC  (60*5) /* 5 minutes FDB timeout */
53195972f6Sopenharmony_ci
54195972f6Sopenharmony_citypedef struct bridgeif_dfdb_entry_s {
55195972f6Sopenharmony_ci  u8_t used;
56195972f6Sopenharmony_ci  u8_t port;
57195972f6Sopenharmony_ci  u32_t ts;
58195972f6Sopenharmony_ci  struct eth_addr addr;
59195972f6Sopenharmony_ci} bridgeif_dfdb_entry_t;
60195972f6Sopenharmony_ci
61195972f6Sopenharmony_citypedef struct bridgeif_dfdb_s {
62195972f6Sopenharmony_ci  u16_t max_fdb_entries;
63195972f6Sopenharmony_ci  bridgeif_dfdb_entry_t *fdb;
64195972f6Sopenharmony_ci} bridgeif_dfdb_t;
65195972f6Sopenharmony_ci
66195972f6Sopenharmony_ci/**
67195972f6Sopenharmony_ci * @ingroup bridgeif_fdb
68195972f6Sopenharmony_ci * A real simple and slow implementation of an auto-learning forwarding database that
69195972f6Sopenharmony_ci * remembers known src mac addresses to know which port to send frames destined for that
70195972f6Sopenharmony_ci * mac address.
71195972f6Sopenharmony_ci *
72195972f6Sopenharmony_ci * ATTENTION: This is meant as an example only, in real-world use, you should
73195972f6Sopenharmony_ci * provide a better implementation :-)
74195972f6Sopenharmony_ci */
75195972f6Sopenharmony_civoid
76195972f6Sopenharmony_cibridgeif_fdb_update_src(void *fdb_ptr, struct eth_addr *src_addr, u8_t port_idx)
77195972f6Sopenharmony_ci{
78195972f6Sopenharmony_ci  int i;
79195972f6Sopenharmony_ci  bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
80195972f6Sopenharmony_ci  BRIDGEIF_DECL_PROTECT(lev);
81195972f6Sopenharmony_ci  BRIDGEIF_READ_PROTECT(lev);
82195972f6Sopenharmony_ci  for (i = 0; i < fdb->max_fdb_entries; i++) {
83195972f6Sopenharmony_ci    bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
84195972f6Sopenharmony_ci    if (e->used && e->ts) {
85195972f6Sopenharmony_ci      if (!memcmp(&e->addr, src_addr, sizeof(struct eth_addr))) {
86195972f6Sopenharmony_ci        LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: update src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
87195972f6Sopenharmony_ci                                         src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
88195972f6Sopenharmony_ci                                         port_idx, i));
89195972f6Sopenharmony_ci        BRIDGEIF_WRITE_PROTECT(lev);
90195972f6Sopenharmony_ci        e->ts = BR_FDB_TIMEOUT_SEC;
91195972f6Sopenharmony_ci        e->port = port_idx;
92195972f6Sopenharmony_ci        BRIDGEIF_WRITE_UNPROTECT(lev);
93195972f6Sopenharmony_ci        BRIDGEIF_READ_UNPROTECT(lev);
94195972f6Sopenharmony_ci        return;
95195972f6Sopenharmony_ci      }
96195972f6Sopenharmony_ci    }
97195972f6Sopenharmony_ci  }
98195972f6Sopenharmony_ci  /* not found, allocate new entry from free */
99195972f6Sopenharmony_ci  for (i = 0; i < fdb->max_fdb_entries; i++) {
100195972f6Sopenharmony_ci    bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
101195972f6Sopenharmony_ci    if (!e->used || !e->ts) {
102195972f6Sopenharmony_ci      BRIDGEIF_WRITE_PROTECT(lev);
103195972f6Sopenharmony_ci      /* check again when protected */
104195972f6Sopenharmony_ci      if (!e->used || !e->ts) {
105195972f6Sopenharmony_ci        LWIP_DEBUGF(BRIDGEIF_FDB_DEBUG, ("br: create src %02x:%02x:%02x:%02x:%02x:%02x (from %d) @ idx %d\n",
106195972f6Sopenharmony_ci                                         src_addr->addr[0], src_addr->addr[1], src_addr->addr[2], src_addr->addr[3], src_addr->addr[4], src_addr->addr[5],
107195972f6Sopenharmony_ci                                         port_idx, i));
108195972f6Sopenharmony_ci        memcpy(&e->addr, src_addr, sizeof(struct eth_addr));
109195972f6Sopenharmony_ci        e->ts = BR_FDB_TIMEOUT_SEC;
110195972f6Sopenharmony_ci        e->port = port_idx;
111195972f6Sopenharmony_ci        e->used = 1;
112195972f6Sopenharmony_ci        BRIDGEIF_WRITE_UNPROTECT(lev);
113195972f6Sopenharmony_ci        BRIDGEIF_READ_UNPROTECT(lev);
114195972f6Sopenharmony_ci        return;
115195972f6Sopenharmony_ci      }
116195972f6Sopenharmony_ci      BRIDGEIF_WRITE_UNPROTECT(lev);
117195972f6Sopenharmony_ci    }
118195972f6Sopenharmony_ci  }
119195972f6Sopenharmony_ci  BRIDGEIF_READ_UNPROTECT(lev);
120195972f6Sopenharmony_ci  /* not found, no free entry -> flood */
121195972f6Sopenharmony_ci}
122195972f6Sopenharmony_ci
123195972f6Sopenharmony_ci/**
124195972f6Sopenharmony_ci * @ingroup bridgeif_fdb
125195972f6Sopenharmony_ci * Walk our list of auto-learnt fdb entries and return a port to forward or BR_FLOOD if unknown
126195972f6Sopenharmony_ci */
127195972f6Sopenharmony_cibridgeif_portmask_t
128195972f6Sopenharmony_cibridgeif_fdb_get_dst_ports(void *fdb_ptr, struct eth_addr *dst_addr)
129195972f6Sopenharmony_ci{
130195972f6Sopenharmony_ci  int i;
131195972f6Sopenharmony_ci  bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)fdb_ptr;
132195972f6Sopenharmony_ci  BRIDGEIF_DECL_PROTECT(lev);
133195972f6Sopenharmony_ci  BRIDGEIF_READ_PROTECT(lev);
134195972f6Sopenharmony_ci  for (i = 0; i < fdb->max_fdb_entries; i++) {
135195972f6Sopenharmony_ci    bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
136195972f6Sopenharmony_ci    if (e->used && e->ts) {
137195972f6Sopenharmony_ci      if (!memcmp(&e->addr, dst_addr, sizeof(struct eth_addr))) {
138195972f6Sopenharmony_ci        bridgeif_portmask_t ret = (bridgeif_portmask_t)(1 << e->port);
139195972f6Sopenharmony_ci        BRIDGEIF_READ_UNPROTECT(lev);
140195972f6Sopenharmony_ci        return ret;
141195972f6Sopenharmony_ci      }
142195972f6Sopenharmony_ci    }
143195972f6Sopenharmony_ci  }
144195972f6Sopenharmony_ci  BRIDGEIF_READ_UNPROTECT(lev);
145195972f6Sopenharmony_ci  return BR_FLOOD;
146195972f6Sopenharmony_ci}
147195972f6Sopenharmony_ci
148195972f6Sopenharmony_ci/**
149195972f6Sopenharmony_ci * @ingroup bridgeif_fdb
150195972f6Sopenharmony_ci * Aging implementation of our simple fdb
151195972f6Sopenharmony_ci */
152195972f6Sopenharmony_cistatic void
153195972f6Sopenharmony_cibridgeif_fdb_age_one_second(void *fdb_ptr)
154195972f6Sopenharmony_ci{
155195972f6Sopenharmony_ci  int i;
156195972f6Sopenharmony_ci  bridgeif_dfdb_t *fdb;
157195972f6Sopenharmony_ci  BRIDGEIF_DECL_PROTECT(lev);
158195972f6Sopenharmony_ci
159195972f6Sopenharmony_ci  fdb = (bridgeif_dfdb_t *)fdb_ptr;
160195972f6Sopenharmony_ci  BRIDGEIF_READ_PROTECT(lev);
161195972f6Sopenharmony_ci
162195972f6Sopenharmony_ci  for (i = 0; i < fdb->max_fdb_entries; i++) {
163195972f6Sopenharmony_ci    bridgeif_dfdb_entry_t *e = &fdb->fdb[i];
164195972f6Sopenharmony_ci    if (e->used && e->ts) {
165195972f6Sopenharmony_ci      BRIDGEIF_WRITE_PROTECT(lev);
166195972f6Sopenharmony_ci      /* check again when protected */
167195972f6Sopenharmony_ci      if (e->used && e->ts) {
168195972f6Sopenharmony_ci        if (--e->ts == 0) {
169195972f6Sopenharmony_ci          e->used = 0;
170195972f6Sopenharmony_ci        }
171195972f6Sopenharmony_ci      }
172195972f6Sopenharmony_ci      BRIDGEIF_WRITE_UNPROTECT(lev);
173195972f6Sopenharmony_ci    }
174195972f6Sopenharmony_ci  }
175195972f6Sopenharmony_ci  BRIDGEIF_READ_UNPROTECT(lev);
176195972f6Sopenharmony_ci}
177195972f6Sopenharmony_ci
178195972f6Sopenharmony_ci/** Timer callback for fdb aging, called once per second */
179195972f6Sopenharmony_cistatic void
180195972f6Sopenharmony_cibridgeif_age_tmr(void *arg)
181195972f6Sopenharmony_ci{
182195972f6Sopenharmony_ci  bridgeif_dfdb_t *fdb = (bridgeif_dfdb_t *)arg;
183195972f6Sopenharmony_ci
184195972f6Sopenharmony_ci  LWIP_ASSERT("invalid arg", arg != NULL);
185195972f6Sopenharmony_ci
186195972f6Sopenharmony_ci  bridgeif_fdb_age_one_second(fdb);
187195972f6Sopenharmony_ci  sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, arg);
188195972f6Sopenharmony_ci}
189195972f6Sopenharmony_ci
190195972f6Sopenharmony_ci/**
191195972f6Sopenharmony_ci * @ingroup bridgeif_fdb
192195972f6Sopenharmony_ci * Init our simple fdb list
193195972f6Sopenharmony_ci */
194195972f6Sopenharmony_civoid *
195195972f6Sopenharmony_cibridgeif_fdb_init(u16_t max_fdb_entries)
196195972f6Sopenharmony_ci{
197195972f6Sopenharmony_ci  bridgeif_dfdb_t *fdb;
198195972f6Sopenharmony_ci  size_t alloc_len_sizet = sizeof(bridgeif_dfdb_t) + (max_fdb_entries * sizeof(bridgeif_dfdb_entry_t));
199195972f6Sopenharmony_ci  mem_size_t alloc_len = (mem_size_t)alloc_len_sizet;
200195972f6Sopenharmony_ci  LWIP_ASSERT("alloc_len == alloc_len_sizet", alloc_len == alloc_len_sizet);
201195972f6Sopenharmony_ci  LWIP_DEBUGF(BRIDGEIF_DEBUG, ("bridgeif_fdb_init: allocating %d bytes for private FDB data\n", (int)alloc_len));
202195972f6Sopenharmony_ci  fdb = (bridgeif_dfdb_t *)mem_calloc(1, alloc_len);
203195972f6Sopenharmony_ci  if (fdb == NULL) {
204195972f6Sopenharmony_ci    return NULL;
205195972f6Sopenharmony_ci  }
206195972f6Sopenharmony_ci  fdb->max_fdb_entries = max_fdb_entries;
207195972f6Sopenharmony_ci  fdb->fdb = (bridgeif_dfdb_entry_t *)(fdb + 1);
208195972f6Sopenharmony_ci
209195972f6Sopenharmony_ci  sys_timeout(BRIDGEIF_AGE_TIMER_MS, bridgeif_age_tmr, fdb);
210195972f6Sopenharmony_ci
211195972f6Sopenharmony_ci  return fdb;
212195972f6Sopenharmony_ci}
213