From 53d80efb439e9eb8d7d4a5913877930edf911f3f Mon Sep 17 00:00:00 2001 From: dlg Date: Wed, 24 Feb 2021 01:20:03 +0000 Subject: [PATCH] add support for adding and deleting address table entries. --- sys/net/if_etherbridge.c | 97 +++++++++++++++++++++++++++++++++++++++- sys/net/if_etherbridge.h | 5 ++- sys/net/if_veb.c | 50 ++++++++++++++++++++- 3 files changed, 149 insertions(+), 3 deletions(-) diff --git a/sys/net/if_etherbridge.c b/sys/net/if_etherbridge.c index 50a4255c610..0912abfda7d 100644 --- a/sys/net/if_etherbridge.c +++ b/sys/net/if_etherbridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_etherbridge.c,v 1.1 2021/02/21 03:26:46 dlg Exp $ */ +/* $OpenBSD: if_etherbridge.c,v 1.2 2021/02/24 01:20:03 dlg Exp $ */ /* * Copyright (c) 2018, 2021 David Gwynne @@ -203,6 +203,12 @@ ebt_insert(struct etherbridge *eb, struct eb_entry *ebe) return (RBT_INSERT(eb_tree, &eb->eb_tree, ebe)); } +static inline struct eb_entry * +ebt_find(struct etherbridge *eb, const struct eb_entry *ebe) +{ + return (RBT_FIND(eb_tree, &eb->eb_tree, ebe)); +} + static inline void ebt_replace(struct etherbridge *eb, struct eb_entry *oebe, struct eb_entry *nebe) @@ -364,6 +370,95 @@ etherbridge_map(struct etherbridge *eb, void *port, } } +int +etherbridge_add_addr(struct etherbridge *eb, void *port, + const struct ether_addr *ea, unsigned int type) +{ + struct eb_list *ebl; + struct eb_entry *nebe; + unsigned int num; + void *nport; + int error = 0; + + if (ETHER_IS_MULTICAST(ea->ether_addr_octet) || + ETHER_IS_EQ(ea->ether_addr_octet, etheranyaddr)) + return (EADDRNOTAVAIL); + + nport = eb_port_take(eb, port); + if (nport == NULL) + return (ENOMEM); + + nebe = pool_get(&eb_entry_pool, PR_NOWAIT); + if (nebe == NULL) { + eb_port_rele(eb, nport); + return (ENOMEM); + } + + smr_init(&nebe->ebe_smr_entry); + refcnt_init(&nebe->ebe_refs); + nebe->ebe_etherbridge = eb; + + nebe->ebe_addr = *ea; + nebe->ebe_port = nport; + nebe->ebe_type = type; + nebe->ebe_age = getuptime(); + + ebl = etherbridge_list(eb, ea); + + mtx_enter(&eb->eb_lock); + num = eb->eb_num + 1; + if (num >= eb->eb_max) + error = ENOSPC; + else if (ebt_insert(eb, nebe) != NULL) + error = EADDRINUSE; + else { + /* we win, do the insert */ + ebl_insert(ebl, nebe); /* give the ref to etherbridge */ + eb->eb_num = num; + } + mtx_leave(&eb->eb_lock); + + if (error != 0) { + /* + * the new entry didnt make it into the + * table, so it can be freed directly. + */ + ebe_free(nebe); + } + + return (error); +} +int +etherbridge_del_addr(struct etherbridge *eb, const struct ether_addr *ea) +{ + struct eb_list *ebl; + struct eb_entry *oebe; + const struct eb_entry key = { + .ebe_addr = *ea, + }; + int error = 0; + + ebl = etherbridge_list(eb, ea); + + mtx_enter(&eb->eb_lock); + oebe = ebt_find(eb, &key); + if (oebe == NULL) + error = ESRCH; + else { + KASSERT(eb->eb_num > 0); + eb->eb_num--; + + ebl_remove(ebl, oebe); /* it's our ref now */ + ebt_remove(eb, oebe); + } + mtx_leave(&eb->eb_lock); + + if (oebe != NULL) + ebe_rele(oebe); + + return (error); +} + static void etherbridge_age(void *arg) { diff --git a/sys/net/if_etherbridge.h b/sys/net/if_etherbridge.h index 6c5b5ef9a21..fa675b48905 100644 --- a/sys/net/if_etherbridge.h +++ b/sys/net/if_etherbridge.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_etherbridge.h,v 1.1 2021/02/21 03:26:46 dlg Exp $ */ +/* $OpenBSD: if_etherbridge.h,v 1.2 2021/02/24 01:20:03 dlg Exp $ */ /* * Copyright (c) 2018, 2021 David Gwynne @@ -92,6 +92,9 @@ int etherbridge_get_max(struct etherbridge *, struct ifbrparam *); int etherbridge_set_tmo(struct etherbridge *, struct ifbrparam *); int etherbridge_get_tmo(struct etherbridge *, struct ifbrparam *); int etherbridge_rtfind(struct etherbridge *, struct ifbaconf *); +int etherbridge_add_addr(struct etherbridge *, void *, + const struct ether_addr *, unsigned int); +int etherbridge_del_addr(struct etherbridge *, const struct ether_addr *); void etherbridge_flush(struct etherbridge *, uint32_t); static inline unsigned int diff --git a/sys/net/if_veb.c b/sys/net/if_veb.c index a32455628a2..b4d043f9c81 100644 --- a/sys/net/if_veb.c +++ b/sys/net/if_veb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_veb.c,v 1.7 2021/02/23 23:42:17 dlg Exp $ */ +/* $OpenBSD: if_veb.c,v 1.8 2021/02/24 01:20:03 dlg Exp $ */ /* * Copyright (c) 2021 David Gwynne @@ -207,6 +207,8 @@ static int veb_port_set_flags(struct veb_softc *, struct ifbreq *); static int veb_port_get_flags(struct veb_softc *, struct ifbreq *); static int veb_port_set_protected(struct veb_softc *, const struct ifbreq *); +static int veb_add_addr(struct veb_softc *, const struct ifbareq *); +static int veb_del_addr(struct veb_softc *, const struct ifbareq *); static int veb_rule_add(struct veb_softc *, const struct ifbrlreq *); static int veb_rule_list_flush(struct veb_softc *, @@ -1148,6 +1150,12 @@ veb_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) etherbridge_flush(&sc->sc_eb, ((struct ifbreq *)data)->ifbr_ifsflags); break; + case SIOCBRDGSADDR: + error = veb_add_addr(sc, (struct ifbareq *)data); + break; + case SIOCBRDGDADDR: + error = veb_del_addr(sc, (struct ifbareq *)data); + break; case SIOCBRDGSIFPROT: error = veb_port_set_protected(sc, (struct ifbreq *)data); @@ -1731,6 +1739,46 @@ veb_port_get_flags(struct veb_softc *sc, struct ifbreq *ifbr) return (0); } +static int +veb_add_addr(struct veb_softc *sc, const struct ifbareq *ifba) +{ + struct veb_port *p; + int error = 0; + unsigned int type; + + if (ISSET(ifba->ifba_flags, ~IFBAF_TYPEMASK)) + return (EINVAL); + switch (ifba->ifba_flags & IFBAF_TYPEMASK) { + case IFBAF_DYNAMIC: + type = EBE_DYNAMIC; + break; + case IFBAF_STATIC: + type = EBE_STATIC; + break; + default: + return (EINVAL); + } + + if (ifba->ifba_dstsa.ss_family != AF_UNSPEC) + return (EAFNOSUPPORT); + + p = veb_port_get(sc, ifba->ifba_ifsname); + if (p == NULL) + return (ESRCH); + + error = etherbridge_add_addr(&sc->sc_eb, p, &ifba->ifba_dst, type); + + veb_port_put(sc, p); + + return (error); +} + +static int +veb_del_addr(struct veb_softc *sc, const struct ifbareq *ifba) +{ + return (etherbridge_del_addr(&sc->sc_eb, &ifba->ifba_dst)); +} + static int veb_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data) { -- 2.20.1