Add a new address cache type called sticky. On an interface marked sticky any
address learned by the bridge is made permanent, the address will not age out and most importantly will not migrate to another interface. This can be used to stop mac address poisoning or clients roaming in much the same way as static entries without the hassle of preloading the table.
This commit is contained in:
parent
2294e5e2a9
commit
e6cf955ad4
@ -320,6 +320,20 @@ unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
|
|||||||
do_bridgeflag(s, val, IFBIF_LEARNING, 0);
|
do_bridgeflag(s, val, IFBIF_LEARNING, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
|
||||||
|
{
|
||||||
|
|
||||||
|
do_bridgeflag(s, val, IFBIF_STICKY, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
|
||||||
|
{
|
||||||
|
|
||||||
|
do_bridgeflag(s, val, IFBIF_STICKY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
|
setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
|
||||||
{
|
{
|
||||||
@ -639,6 +653,8 @@ static struct cmd bridge_cmds[] = {
|
|||||||
DEF_CMD_ARG("-discover", unsetbridge_discover),
|
DEF_CMD_ARG("-discover", unsetbridge_discover),
|
||||||
DEF_CMD_ARG("learn", setbridge_learn),
|
DEF_CMD_ARG("learn", setbridge_learn),
|
||||||
DEF_CMD_ARG("-learn", unsetbridge_learn),
|
DEF_CMD_ARG("-learn", unsetbridge_learn),
|
||||||
|
DEF_CMD_ARG("sticky", setbridge_sticky),
|
||||||
|
DEF_CMD_ARG("-sticky", unsetbridge_sticky),
|
||||||
DEF_CMD_ARG("span", setbridge_span),
|
DEF_CMD_ARG("span", setbridge_span),
|
||||||
DEF_CMD_ARG("-span", unsetbridge_span),
|
DEF_CMD_ARG("-span", unsetbridge_span),
|
||||||
DEF_CMD_ARG("stp", setbridge_stp),
|
DEF_CMD_ARG("stp", setbridge_stp),
|
||||||
|
@ -1245,6 +1245,18 @@ This is the default for all interfaces added to a bridge.
|
|||||||
Clear the
|
Clear the
|
||||||
.Dq learning
|
.Dq learning
|
||||||
attribute on a member interface.
|
attribute on a member interface.
|
||||||
|
.It Cm sticky Ar interface
|
||||||
|
Mark an interface as a
|
||||||
|
.Dq sticky
|
||||||
|
interface.
|
||||||
|
Dynamically learned address entries are treated at static once entered into
|
||||||
|
the cache.
|
||||||
|
Sticky entries are never aged out of the cache or replaced, even if the
|
||||||
|
address is seen on a different interface.
|
||||||
|
.It Cm -sticky Ar interface
|
||||||
|
Clear the
|
||||||
|
.Dq sticky
|
||||||
|
attribute on a member interface.
|
||||||
.It Cm span Ar interface
|
.It Cm span Ar interface
|
||||||
Add the interface named by
|
Add the interface named by
|
||||||
.Ar interface
|
.Ar interface
|
||||||
|
@ -250,7 +250,7 @@ static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
|
|||||||
static void bridge_span(struct bridge_softc *, struct mbuf *);
|
static void bridge_span(struct bridge_softc *, struct mbuf *);
|
||||||
|
|
||||||
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
|
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
|
||||||
struct ifnet *, int, uint8_t);
|
struct bridge_iflist *, int, uint8_t);
|
||||||
static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *);
|
static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *);
|
||||||
static void bridge_rttrim(struct bridge_softc *);
|
static void bridge_rttrim(struct bridge_softc *);
|
||||||
static void bridge_rtage(struct bridge_softc *);
|
static void bridge_rtage(struct bridge_softc *);
|
||||||
@ -1194,7 +1194,7 @@ bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
|
|||||||
if (bif == NULL)
|
if (bif == NULL)
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
|
|
||||||
error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1,
|
error = bridge_rtupdate(sc, req->ifba_dst, bif, 1,
|
||||||
req->ifba_flags);
|
req->ifba_flags);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
@ -1901,7 +1901,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
|
|||||||
eh->ether_shost[4] == 0 &&
|
eh->ether_shost[4] == 0 &&
|
||||||
eh->ether_shost[5] == 0) == 0) {
|
eh->ether_shost[5] == 0) == 0) {
|
||||||
(void) bridge_rtupdate(sc, eh->ether_shost,
|
(void) bridge_rtupdate(sc, eh->ether_shost,
|
||||||
src_if, 0, IFBAF_DYNAMIC);
|
bif, 0, IFBAF_DYNAMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((bif->bif_flags & IFBIF_STP) != 0 &&
|
if ((bif->bif_flags & IFBIF_STP) != 0 &&
|
||||||
@ -2014,7 +2014,7 @@ static struct mbuf *
|
|||||||
bridge_input(struct ifnet *ifp, struct mbuf *m)
|
bridge_input(struct ifnet *ifp, struct mbuf *m)
|
||||||
{
|
{
|
||||||
struct bridge_softc *sc = ifp->if_bridge;
|
struct bridge_softc *sc = ifp->if_bridge;
|
||||||
struct bridge_iflist *bif;
|
struct bridge_iflist *bif, *bif2;
|
||||||
struct ifnet *bifp;
|
struct ifnet *bifp;
|
||||||
struct ether_header *eh;
|
struct ether_header *eh;
|
||||||
struct mbuf *mc, *mc2;
|
struct mbuf *mc, *mc2;
|
||||||
@ -2058,7 +2058,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
|
|||||||
/* Note where to send the reply to */
|
/* Note where to send the reply to */
|
||||||
if (bif->bif_flags & IFBIF_LEARNING)
|
if (bif->bif_flags & IFBIF_LEARNING)
|
||||||
(void) bridge_rtupdate(sc,
|
(void) bridge_rtupdate(sc,
|
||||||
eh->ether_shost, ifp, 0, IFBAF_DYNAMIC);
|
eh->ether_shost, bif, 0, IFBAF_DYNAMIC);
|
||||||
|
|
||||||
/* Mark the packet as arriving on the bridge interface */
|
/* Mark the packet as arriving on the bridge interface */
|
||||||
m->m_pkthdr.rcvif = bifp;
|
m->m_pkthdr.rcvif = bifp;
|
||||||
@ -2140,31 +2140,31 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
|
|||||||
/*
|
/*
|
||||||
* Unicast. Make sure it's not for us.
|
* Unicast. Make sure it's not for us.
|
||||||
*/
|
*/
|
||||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
|
||||||
if (bif->bif_ifp->if_type == IFT_GIF)
|
if (bif2->bif_ifp->if_type == IFT_GIF)
|
||||||
continue;
|
continue;
|
||||||
/* It is destined for us. */
|
/* It is destined for us. */
|
||||||
if (memcmp(IF_LLADDR(bif->bif_ifp), eh->ether_dhost,
|
if (memcmp(IF_LLADDR(bif2->bif_ifp), eh->ether_dhost,
|
||||||
ETHER_ADDR_LEN) == 0
|
ETHER_ADDR_LEN) == 0
|
||||||
#ifdef DEV_CARP
|
#ifdef DEV_CARP
|
||||||
|| (bif->bif_ifp->if_carp
|
|| (bif2->bif_ifp->if_carp
|
||||||
&& carp_forus(bif->bif_ifp->if_carp, eh->ether_dhost))
|
&& carp_forus(bif2->bif_ifp->if_carp, eh->ether_dhost))
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
if (bif->bif_flags & IFBIF_LEARNING)
|
if (bif->bif_flags & IFBIF_LEARNING)
|
||||||
(void) bridge_rtupdate(sc,
|
(void) bridge_rtupdate(sc,
|
||||||
eh->ether_shost, ifp, 0, IFBAF_DYNAMIC);
|
eh->ether_shost, bif, 0, IFBAF_DYNAMIC);
|
||||||
m->m_pkthdr.rcvif = bif->bif_ifp;
|
m->m_pkthdr.rcvif = bif2->bif_ifp;
|
||||||
BRIDGE_UNLOCK(sc);
|
BRIDGE_UNLOCK(sc);
|
||||||
return (m);
|
return (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We just received a packet that we sent out. */
|
/* We just received a packet that we sent out. */
|
||||||
if (memcmp(IF_LLADDR(bif->bif_ifp), eh->ether_shost,
|
if (memcmp(IF_LLADDR(bif2->bif_ifp), eh->ether_shost,
|
||||||
ETHER_ADDR_LEN) == 0
|
ETHER_ADDR_LEN) == 0
|
||||||
#ifdef DEV_CARP
|
#ifdef DEV_CARP
|
||||||
|| (bif->bif_ifp->if_carp
|
|| (bif2->bif_ifp->if_carp
|
||||||
&& carp_forus(bif->bif_ifp->if_carp, eh->ether_shost))
|
&& carp_forus(bif2->bif_ifp->if_carp, eh->ether_shost))
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
BRIDGE_UNLOCK(sc);
|
BRIDGE_UNLOCK(sc);
|
||||||
@ -2315,9 +2315,10 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
|
bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
|
||||||
struct ifnet *dst_if, int setflags, uint8_t flags)
|
struct bridge_iflist *bif, int setflags, uint8_t flags)
|
||||||
{
|
{
|
||||||
struct bridge_rtnode *brt;
|
struct bridge_rtnode *brt;
|
||||||
|
struct ifnet *dst_if = bif->bif_ifp;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
BRIDGE_LOCK_ASSERT(sc);
|
BRIDGE_LOCK_ASSERT(sc);
|
||||||
@ -2341,7 +2342,12 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
|
|||||||
if (brt == NULL)
|
if (brt == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
|
|
||||||
brt->brt_flags = IFBAF_DYNAMIC;
|
if (bif->bif_flags & IFBIF_STICKY)
|
||||||
|
brt->brt_flags = IFBAF_STICKY;
|
||||||
|
else
|
||||||
|
brt->brt_flags = IFBAF_DYNAMIC;
|
||||||
|
|
||||||
|
brt->brt_ifp = dst_if;
|
||||||
memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
|
memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
|
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
|
||||||
|
@ -140,8 +140,9 @@ struct ifbreq {
|
|||||||
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
|
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
|
||||||
#define IFBIF_STP 0x04 /* if participates in spanning tree */
|
#define IFBIF_STP 0x04 /* if participates in spanning tree */
|
||||||
#define IFBIF_SPAN 0x08 /* if is a span port */
|
#define IFBIF_SPAN 0x08 /* if is a span port */
|
||||||
|
#define IFBIF_STICKY 0x10 /* if learned addresses stick */
|
||||||
|
|
||||||
#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3STP\4SPAN"
|
#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3STP\4SPAN\5STICKY"
|
||||||
|
|
||||||
/* BRDGFLUSH */
|
/* BRDGFLUSH */
|
||||||
#define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */
|
#define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */
|
||||||
@ -173,8 +174,9 @@ struct ifbareq {
|
|||||||
#define IFBAF_TYPEMASK 0x03 /* address type mask */
|
#define IFBAF_TYPEMASK 0x03 /* address type mask */
|
||||||
#define IFBAF_DYNAMIC 0x00 /* dynamically learned address */
|
#define IFBAF_DYNAMIC 0x00 /* dynamically learned address */
|
||||||
#define IFBAF_STATIC 0x01 /* static address */
|
#define IFBAF_STATIC 0x01 /* static address */
|
||||||
|
#define IFBAF_STICKY 0x02 /* sticky address */
|
||||||
|
|
||||||
#define IFBAFBITS "\020\1STATIC"
|
#define IFBAFBITS "\020\1STATIC\2STICKY"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Address list structure.
|
* Address list structure.
|
||||||
|
Loading…
Reference in New Issue
Block a user