Implement multicast support in mvpp(4) to make IPv6 work. With this
authorpatrick <patrick@openbsd.org>
Thu, 3 Jun 2021 21:42:23 +0000 (21:42 +0000)
committerpatrick <patrick@openbsd.org>
Thu, 3 Jun 2021 21:42:23 +0000 (21:42 +0000)
change it's also not necessary to remember the old lladdr, since the
old one will be purged automatically prior to installing the current
set of multicast addresses.

Complaint filed by matthieu@

sys/dev/fdt/if_mvpp.c
sys/dev/fdt/if_mvppreg.h

index 0350b46..1894dd2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_mvpp.c,v 1.45 2021/06/02 21:41:38 kettenis Exp $   */
+/*     $OpenBSD: if_mvpp.c,v 1.46 2021/06/03 21:42:23 patrick Exp $    */
 /*
  * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
  * Copyright (c) 2017, 2020 Patrick Wildt <patrick@blueri.se>
@@ -194,7 +194,6 @@ struct mvpp2_port {
        struct mii_data         sc_mii;
 #define sc_media       sc_mii.mii_media
        struct mii_bus          *sc_mdio;
-       char                    sc_cur_lladdr[ETHER_ADDR_LEN];
 
        enum {
                PHY_MODE_XAUI,
@@ -419,6 +418,7 @@ int mvpp2_prs_mac_da_range_find(struct mvpp2_softc *, int, const uint8_t *,
 int    mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *, const uint8_t *,
            uint8_t *);
 int    mvpp2_prs_mac_da_accept(struct mvpp2_port *, const uint8_t *, int);
+void   mvpp2_prs_mac_del_all(struct mvpp2_port *);
 int    mvpp2_prs_tag_mode_set(struct mvpp2_softc *, int, int);
 int    mvpp2_prs_def_flow(struct mvpp2_port *);
 void   mvpp2_cls_flow_write(struct mvpp2_softc *, struct mvpp2_cls_flow_entry *);
@@ -2279,10 +2279,9 @@ mvpp2_up(struct mvpp2_port *sc)
                sfp_enable(sc->sc_sfp);
                rw_exit(&mvpp2_sff_lock);
        }
-       
-       memcpy(sc->sc_cur_lladdr, sc->sc_lladdr, ETHER_ADDR_LEN);
+
        mvpp2_prs_mac_da_accept(sc, etherbroadcastaddr, 1);
-       mvpp2_prs_mac_da_accept(sc, sc->sc_cur_lladdr, 1);
+       mvpp2_prs_mac_da_accept(sc, sc->sc_lladdr, 1);
        mvpp2_prs_tag_mode_set(sc->sc, sc->sc_id, MVPP2_TAG_TYPE_MH);
        mvpp2_prs_def_flow(sc);
 
@@ -2904,8 +2903,6 @@ mvpp2_down(struct mvpp2_port *sc)
        for (i = 0; i < sc->sc_nrxq; i++)
                mvpp2_rxq_hw_deinit(sc, &sc->sc_rxqs[i]);
 
-       mvpp2_prs_mac_da_accept(sc, sc->sc_cur_lladdr, 0);
-
        if (sc->sc_sfp) {
                rw_enter(&mvpp2_sff_lock, RW_WRITE);
                sfp_disable(sc->sc_sfp);
@@ -3062,12 +3059,40 @@ mvpp2_rxq_short_pool_set(struct mvpp2_port *port, int lrxq, int pool)
 void
 mvpp2_iff(struct mvpp2_port *sc)
 {
-       /* FIXME: multicast handling */
+       struct arpcom *ac = &sc->sc_ac;
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       struct ether_multi *enm;
+       struct ether_multistep step;
+
+       ifp->if_flags &= ~IFF_ALLMULTI;
+
+       /* Removes all but broadcast and (new) lladdr */
+       mvpp2_prs_mac_del_all(sc);
 
-       if (memcmp(sc->sc_cur_lladdr, sc->sc_lladdr, ETHER_ADDR_LEN) != 0) {
-               mvpp2_prs_mac_da_accept(sc, sc->sc_cur_lladdr, 0);
-               memcpy(sc->sc_cur_lladdr, sc->sc_lladdr, ETHER_ADDR_LEN);
-               mvpp2_prs_mac_da_accept(sc, sc->sc_cur_lladdr, 1);
+       if (ifp->if_flags & IFF_PROMISC) {
+               mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
+                   MVPP2_PRS_L2_UNI_CAST, 1);
+               mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
+                   MVPP2_PRS_L2_MULTI_CAST, 1);
+               return;
+       }
+
+       mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
+           MVPP2_PRS_L2_UNI_CAST, 0);
+       mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
+           MVPP2_PRS_L2_MULTI_CAST, 0);
+
+       if (ac->ac_multirangecnt > 0 ||
+           ac->ac_multicnt > MVPP2_PRS_MAC_MC_FILT_MAX) {
+               ifp->if_flags |= IFF_ALLMULTI;
+               mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
+                   MVPP2_PRS_L2_MULTI_CAST, 1);
+       } else {
+               ETHER_FIRST_MULTI(step, ac, enm);
+               while (enm != NULL) {
+                       mvpp2_prs_mac_da_accept(sc, enm->enm_addrlo, 1);
+                       ETHER_NEXT_MULTI(step, enm);
+               }
        }
 }
 
@@ -4347,7 +4372,7 @@ mvpp2_prs_mac_da_range_find(struct mvpp2_softc *sc, int pmap, const uint8_t *da,
        struct mvpp2_prs_entry pe;
        int tid;
 
-       for (tid = MVPP2_PE_FIRST_FREE_TID; tid <= MVPP2_PE_LAST_FREE_TID;
+       for (tid = MVPP2_PE_MAC_RANGE_START; tid <= MVPP2_PE_MAC_RANGE_END;
            tid++) {
                uint32_t entry_pmap;
 
@@ -4383,8 +4408,8 @@ mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const uint8_t *da, int add)
                if (!add)
                        return 0;
 
-               tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
-                   MVPP2_PE_LAST_FREE_TID);
+               tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_MAC_RANGE_START,
+                   MVPP2_PE_MAC_RANGE_END);
                if (tid < 0)
                        return tid;
 
@@ -4434,6 +4459,40 @@ mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const uint8_t *da, int add)
        return 0;
 }
 
+void
+mvpp2_prs_mac_del_all(struct mvpp2_port *port)
+{
+       struct mvpp2_softc *sc = port->sc;
+       struct mvpp2_prs_entry pe;
+       uint32_t pmap;
+       int index, tid;
+
+       for (tid = MVPP2_PE_MAC_RANGE_START; tid <= MVPP2_PE_MAC_RANGE_END;
+           tid++) {
+               uint8_t da[ETHER_ADDR_LEN], da_mask[ETHER_ADDR_LEN];
+
+               if (!sc->sc_prs_shadow[tid].valid ||
+                   (sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
+                   (sc->sc_prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
+                       continue;
+
+               mvpp2_prs_hw_read(sc, &pe, tid);
+               pmap = mvpp2_prs_tcam_port_map_get(&pe);
+
+               if (!(pmap & (1 << port->sc_id)))
+                       continue;
+
+               for (index = 0; index < ETHER_ADDR_LEN; index++)
+                       mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
+                           &da_mask[index]);
+
+               if (ETHER_IS_BROADCAST(da) || ETHER_IS_EQ(da, port->sc_lladdr))
+                       continue;
+
+               mvpp2_prs_mac_da_accept(port, da, 0);
+       }
+}
+
 int
 mvpp2_prs_tag_mode_set(struct mvpp2_softc *sc, int port_id, int type)
 {
index d50b927..1c3b8b5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_mvppreg.h,v 1.15 2020/11/08 00:49:41 patrick Exp $ */
+/*     $OpenBSD: if_mvppreg.h,v 1.16 2021/06/03 21:42:23 patrick Exp $ */
 /*
  * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
  * Copyright (c) 2017, 2020 Patrick Wildt <patrick@blueri.se>
@@ -993,6 +993,10 @@ enum mvpp2_prs_l3_cast {
 #define MVPP2_PRS_MCAST_VAL            BIT(0)
 #define MVPP2_PRS_UCAST_VAL            0x0
 
+#define MVPP2_PRS_MAC_RANGE_SIZE       80
+#define MVPP2_PRS_MAC_UC_FILT_MAX      4
+#define MVPP2_PRS_MAC_MC_FILT_MAX      21
+
 /*
  * Tcam structure:
  * - lookup ID - 4 bits
@@ -1014,7 +1018,10 @@ enum mvpp2_prs_l3_cast {
 /* Tcam entries ID */
 #define MVPP2_PE_DROP_ALL              0
 #define MVPP2_PE_FIRST_FREE_TID                1
-#define MVPP2_PE_LAST_FREE_TID         (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
+#define MVPP2_PE_LAST_FREE_TID         (MVPP2_PE_MAC_RANGE_START - 1)
+#define MVPP2_PE_MAC_RANGE_END         (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
+#define MVPP2_PE_MAC_RANGE_START       (MVPP2_PE_MAC_RANGE_END - \
+                                               MVPP2_PRS_MAC_RANGE_SIZE + 1)
 #define MVPP2_PE_IP6_EXT_PROTO_UN      (MVPP2_PRS_TCAM_SRAM_SIZE - 30)
 #define MVPP2_PE_IP6_ADDR_UN           (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
 #define MVPP2_PE_IP4_ADDR_UN           (MVPP2_PRS_TCAM_SRAM_SIZE - 28)