add support for adding and deleting address table entries.
authordlg <dlg@openbsd.org>
Wed, 24 Feb 2021 01:20:03 +0000 (01:20 +0000)
committerdlg <dlg@openbsd.org>
Wed, 24 Feb 2021 01:20:03 +0000 (01:20 +0000)
sys/net/if_etherbridge.c
sys/net/if_etherbridge.h
sys/net/if_veb.c

index 50a4255..0912abf 100644 (file)
@@ -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 <dlg@openbsd.org>
@@ -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)
 {
index 6c5b5ef..fa675b4 100644 (file)
@@ -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 <dlg@openbsd.org>
@@ -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
index a324556..b4d043f 100644 (file)
@@ -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 <dlg@openbsd.org>
@@ -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)
 {