Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  lan966x_mdb.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+

#include <net/switchdev.h>

#include "lan966x_main.h"

struct lan966x_pgid_entry {
 struct list_head list;
 int index;
 refcount_t refcount;
 u16 ports;
};

struct lan966x_mdb_entry {
 struct list_head list;
 unsigned char mac[ETH_ALEN];
 u16 vid;
 u16 ports;
 struct lan966x_pgid_entry *pgid;
 u8 cpu_copy;
};

void lan966x_mdb_init(struct lan966x *lan966x)
{
 INIT_LIST_HEAD(&lan966x->mdb_entries);
 INIT_LIST_HEAD(&lan966x->pgid_entries);
}

static void lan966x_mdb_purge_mdb_entries(struct lan966x *lan966x)
{
 struct lan966x_mdb_entry *mdb_entry, *tmp;

 list_for_each_entry_safe(mdb_entry, tmp, &lan966x->mdb_entries, list) {
  list_del(&mdb_entry->list);
  kfree(mdb_entry);
 }
}

static void lan966x_mdb_purge_pgid_entries(struct lan966x *lan966x)
{
 struct lan966x_pgid_entry *pgid_entry, *tmp;

 list_for_each_entry_safe(pgid_entry, tmp, &lan966x->pgid_entries, list) {
  list_del(&pgid_entry->list);
  kfree(pgid_entry);
 }
}

void lan966x_mdb_deinit(struct lan966x *lan966x)
{
 lan966x_mdb_purge_mdb_entries(lan966x);
 lan966x_mdb_purge_pgid_entries(lan966x);
}

static struct lan966x_mdb_entry *
lan966x_mdb_entry_get(struct lan966x *lan966x,
        const unsigned char *mac,
        u16 vid)
{
 struct lan966x_mdb_entry *mdb_entry;

 list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  if (ether_addr_equal(mdb_entry->mac, mac) &&
      mdb_entry->vid == vid)
   return mdb_entry;
 }

 return NULL;
}

static struct lan966x_mdb_entry *
lan966x_mdb_entry_add(struct lan966x *lan966x,
        const struct switchdev_obj_port_mdb *mdb)
{
 struct lan966x_mdb_entry *mdb_entry;

 mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
 if (!mdb_entry)
  return ERR_PTR(-ENOMEM);

 ether_addr_copy(mdb_entry->mac, mdb->addr);
 mdb_entry->vid = mdb->vid;

 list_add_tail(&mdb_entry->list, &lan966x->mdb_entries);

 return mdb_entry;
}

static void lan966x_mdb_encode_mac(unsigned char *mac,
       struct lan966x_mdb_entry *mdb_entry,
       enum macaccess_entry_type type)
{
 ether_addr_copy(mac, mdb_entry->mac);

 if (type == ENTRYTYPE_MACV4) {
  mac[0] = 0;
  mac[1] = mdb_entry->ports >> 8;
  mac[2] = mdb_entry->ports & 0xff;
 } else if (type == ENTRYTYPE_MACV6) {
  mac[0] = mdb_entry->ports >> 8;
  mac[1] = mdb_entry->ports & 0xff;
 }
}

static int lan966x_mdb_ip_add(struct lan966x_port *port,
         const struct switchdev_obj_port_mdb *mdb,
         enum macaccess_entry_type type)
{
 bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
 struct lan966x *lan966x = port->lan966x;
 struct lan966x_mdb_entry *mdb_entry;
 unsigned char mac[ETH_ALEN];
 bool cpu_copy = false;

 mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
 if (!mdb_entry) {
  mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
  if (IS_ERR(mdb_entry))
   return PTR_ERR(mdb_entry);
 } else {
  lan966x_mdb_encode_mac(mac, mdb_entry, type);
  lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 }

 if (cpu_port)
  mdb_entry->cpu_copy++;
 else
  mdb_entry->ports |= BIT(port->chip_port);

 /* Copy the frame to CPU only if the CPU is in the VLAN */
 if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
     mdb_entry->cpu_copy)
  cpu_copy = true;

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 return lan966x_mac_ip_learn(lan966x, cpu_copy,
        mac, mdb_entry->vid, type);
}

static int lan966x_mdb_ip_del(struct lan966x_port *port,
         const struct switchdev_obj_port_mdb *mdb,
         enum macaccess_entry_type type)
{
 bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
 struct lan966x *lan966x = port->lan966x;
 struct lan966x_mdb_entry *mdb_entry;
 unsigned char mac[ETH_ALEN];
 u16 ports;

 mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
 if (!mdb_entry)
  return -ENOENT;

 ports = mdb_entry->ports;
 if (cpu_port) {
  /* If there are still other references to the CPU port then
 * there is no point to delete and add again the same entry
 */

  mdb_entry->cpu_copy--;
  if (mdb_entry->cpu_copy)
   return 0;
 } else {
  ports &= ~BIT(port->chip_port);
 }

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);

 mdb_entry->ports = ports;

 if (!mdb_entry->ports && !mdb_entry->cpu_copy) {
  list_del(&mdb_entry->list);
  kfree(mdb_entry);
  return 0;
 }

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 return lan966x_mac_ip_learn(lan966x, mdb_entry->cpu_copy,
        mac, mdb_entry->vid, type);
}

static struct lan966x_pgid_entry *
lan966x_pgid_entry_add(struct lan966x *lan966x, int index, u16 ports)
{
 struct lan966x_pgid_entry *pgid_entry;

 pgid_entry = kzalloc(sizeof(*pgid_entry), GFP_KERNEL);
 if (!pgid_entry)
  return ERR_PTR(-ENOMEM);

 pgid_entry->ports = ports;
 pgid_entry->index = index;
 refcount_set(&pgid_entry->refcount, 1);

 list_add_tail(&pgid_entry->list, &lan966x->pgid_entries);

 return pgid_entry;
}

static struct lan966x_pgid_entry *
lan966x_pgid_entry_get(struct lan966x *lan966x,
         struct lan966x_mdb_entry *mdb_entry)
{
 struct lan966x_pgid_entry *pgid_entry;
 int index;

 /* Try to find an existing pgid that uses the same ports as the
 * mdb_entry
 */

 list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
  if (pgid_entry->ports == mdb_entry->ports) {
   refcount_inc(&pgid_entry->refcount);
   return pgid_entry;
  }
 }

 /* Try to find an empty pgid entry and allocate one in case it finds it,
 * otherwise it means that there are no more resources
 */

 for (index = PGID_GP_START; index < PGID_GP_END; index++) {
  bool used = false;

  list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
   if (pgid_entry->index == index) {
    used = true;
    break;
   }
  }

  if (!used)
   return lan966x_pgid_entry_add(lan966x, index,
            mdb_entry->ports);
 }

 return ERR_PTR(-ENOSPC);
}

static void lan966x_pgid_entry_del(struct lan966x *lan966x,
       struct lan966x_pgid_entry *pgid_entry)
{
 if (!refcount_dec_and_test(&pgid_entry->refcount))
  return;

 list_del(&pgid_entry->list);
 kfree(pgid_entry);
}

static int lan966x_mdb_l2_add(struct lan966x_port *port,
         const struct switchdev_obj_port_mdb *mdb,
         enum macaccess_entry_type type)
{
 bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
 struct lan966x *lan966x = port->lan966x;
 struct lan966x_pgid_entry *pgid_entry;
 struct lan966x_mdb_entry *mdb_entry;
 unsigned char mac[ETH_ALEN];

 mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
 if (!mdb_entry) {
  mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
  if (IS_ERR(mdb_entry))
   return PTR_ERR(mdb_entry);
 } else {
  lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
  lan966x_mdb_encode_mac(mac, mdb_entry, type);
  lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 }

 if (cpu_port) {
  mdb_entry->ports |= BIT(CPU_PORT);
  mdb_entry->cpu_copy++;
 } else {
  mdb_entry->ports |= BIT(port->chip_port);
 }

 pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
 if (IS_ERR(pgid_entry)) {
  list_del(&mdb_entry->list);
  kfree(mdb_entry);
  return PTR_ERR(pgid_entry);
 }
 mdb_entry->pgid = pgid_entry;

 /* Copy the frame to CPU only if the CPU is in the VLAN */
 if (!lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
     mdb_entry->cpu_copy)
  mdb_entry->ports &= BIT(CPU_PORT);

 lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  ANA_PGID_PGID,
  lan966x, ANA_PGID(pgid_entry->index));

 return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
     mdb_entry->vid, type);
}

static int lan966x_mdb_l2_del(struct lan966x_port *port,
         const struct switchdev_obj_port_mdb *mdb,
         enum macaccess_entry_type type)
{
 bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
 struct lan966x *lan966x = port->lan966x;
 struct lan966x_pgid_entry *pgid_entry;
 struct lan966x_mdb_entry *mdb_entry;
 unsigned char mac[ETH_ALEN];
 u16 ports;

 mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
 if (!mdb_entry)
  return -ENOENT;

 ports = mdb_entry->ports;
 if (cpu_port) {
  /* If there are still other references to the CPU port then
 * there is no point to delete and add again the same entry
 */

  mdb_entry->cpu_copy--;
  if (mdb_entry->cpu_copy)
   return 0;

  ports &= ~BIT(CPU_PORT);
 } else {
  ports &= ~BIT(port->chip_port);
 }

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);

 mdb_entry->ports = ports;

 if (!mdb_entry->ports) {
  list_del(&mdb_entry->list);
  kfree(mdb_entry);
  return 0;
 }

 pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
 if (IS_ERR(pgid_entry)) {
  list_del(&mdb_entry->list);
  kfree(mdb_entry);
  return PTR_ERR(pgid_entry);
 }
 mdb_entry->pgid = pgid_entry;

 lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  ANA_PGID_PGID,
  lan966x, ANA_PGID(pgid_entry->index));

 return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
     mdb_entry->vid, type);
}

static enum macaccess_entry_type
lan966x_mdb_classify(const unsigned char *mac)
{
 if (mac[0] == 0x01 && mac[1] == 0x00 && mac[2] == 0x5e)
  return ENTRYTYPE_MACV4;
 if (mac[0] == 0x33 && mac[1] == 0x33)
  return ENTRYTYPE_MACV6;
 return ENTRYTYPE_LOCKED;
}

int lan966x_handle_port_mdb_add(struct lan966x_port *port,
    const struct switchdev_obj *obj)
{
 const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
 enum macaccess_entry_type type;

 /* Split the way the entries are added for ipv4/ipv6 and for l2. The
 * reason is that for ipv4/ipv6 it doesn't require to use any pgid
 * entry, while for l2 is required to use pgid entries
 */

 type = lan966x_mdb_classify(mdb->addr);
 if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  return lan966x_mdb_ip_add(port, mdb, type);

 return lan966x_mdb_l2_add(port, mdb, type);
}

int lan966x_handle_port_mdb_del(struct lan966x_port *port,
    const struct switchdev_obj *obj)
{
 const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
 enum macaccess_entry_type type;

 /* Split the way the entries are removed for ipv4/ipv6 and for l2. The
 * reason is that for ipv4/ipv6 it doesn't require to use any pgid
 * entry, while for l2 is required to use pgid entries
 */

 type = lan966x_mdb_classify(mdb->addr);
 if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
  return lan966x_mdb_ip_del(port, mdb, type);

 return lan966x_mdb_l2_del(port, mdb, type);
}

static void lan966x_mdb_ip_cpu_copy(struct lan966x *lan966x,
        struct lan966x_mdb_entry *mdb_entry,
        enum macaccess_entry_type type)
{
 unsigned char mac[ETH_ALEN];

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 lan966x_mac_ip_learn(lan966x, true, mac, mdb_entry->vid, type);
}

static void lan966x_mdb_l2_cpu_copy(struct lan966x *lan966x,
        struct lan966x_mdb_entry *mdb_entry,
        enum macaccess_entry_type type)
{
 struct lan966x_pgid_entry *pgid_entry;
 unsigned char mac[ETH_ALEN];

 lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);

 mdb_entry->ports |= BIT(CPU_PORT);

 pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
 if (IS_ERR(pgid_entry))
  return;

 mdb_entry->pgid = pgid_entry;

 lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  ANA_PGID_PGID,
  lan966x, ANA_PGID(pgid_entry->index));

 lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
     mdb_entry->vid, type);
}

void lan966x_mdb_write_entries(struct lan966x *lan966x, u16 vid)
{
 struct lan966x_mdb_entry *mdb_entry;
 enum macaccess_entry_type type;

 list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
   continue;

  type = lan966x_mdb_classify(mdb_entry->mac);
  if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
   lan966x_mdb_ip_cpu_copy(lan966x, mdb_entry, type);
  else
   lan966x_mdb_l2_cpu_copy(lan966x, mdb_entry, type);
 }
}

static void lan966x_mdb_ip_cpu_remove(struct lan966x *lan966x,
          struct lan966x_mdb_entry *mdb_entry,
          enum macaccess_entry_type type)
{
 unsigned char mac[ETH_ALEN];

 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 lan966x_mac_ip_learn(lan966x, false, mac, mdb_entry->vid, type);
}

static void lan966x_mdb_l2_cpu_remove(struct lan966x *lan966x,
          struct lan966x_mdb_entry *mdb_entry,
          enum macaccess_entry_type type)
{
 struct lan966x_pgid_entry *pgid_entry;
 unsigned char mac[ETH_ALEN];

 lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
 lan966x_mdb_encode_mac(mac, mdb_entry, type);
 lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);

 mdb_entry->ports &= ~BIT(CPU_PORT);

 pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
 if (IS_ERR(pgid_entry))
  return;

 mdb_entry->pgid = pgid_entry;

 lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
  ANA_PGID_PGID,
  lan966x, ANA_PGID(pgid_entry->index));

 lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
     mdb_entry->vid, type);
}

void lan966x_mdb_erase_entries(struct lan966x *lan966x, u16 vid)
{
 struct lan966x_mdb_entry *mdb_entry;
 enum macaccess_entry_type type;

 list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
   continue;

  type = lan966x_mdb_classify(mdb_entry->mac);
  if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
   lan966x_mdb_ip_cpu_remove(lan966x, mdb_entry, type);
  else
   lan966x_mdb_l2_cpu_remove(lan966x, mdb_entry, type);
 }
}

void lan966x_mdb_clear_entries(struct lan966x *lan966x)
{
 struct lan966x_mdb_entry *mdb_entry;
 enum macaccess_entry_type type;
 unsigned char mac[ETH_ALEN];

 list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  type = lan966x_mdb_classify(mdb_entry->mac);

  lan966x_mdb_encode_mac(mac, mdb_entry, type);
  /* Remove just the MAC entry, still keep the PGID in case of L2
 * entries because this can be restored at later point
 */

  lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
 }
}

void lan966x_mdb_restore_entries(struct lan966x *lan966x)
{
 struct lan966x_mdb_entry *mdb_entry;
 enum macaccess_entry_type type;
 unsigned char mac[ETH_ALEN];
 bool cpu_copy = false;

 list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
  type = lan966x_mdb_classify(mdb_entry->mac);

  lan966x_mdb_encode_mac(mac, mdb_entry, type);
  if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6) {
   /* Copy the frame to CPU only if the CPU is in the VLAN */
   if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x,
          mdb_entry->vid) &&
       mdb_entry->cpu_copy)
    cpu_copy = true;

   lan966x_mac_ip_learn(lan966x, cpu_copy, mac,
          mdb_entry->vid, type);
  } else {
   lan966x_mac_learn(lan966x, mdb_entry->pgid->index,
       mdb_entry->mac,
       mdb_entry->vid, type);
  }
 }
}

Messung V0.5
C=95 H=99 G=96

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge