root/drivers/net/ethernet/marvell/prestera/prestera_router_hw.h
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved. */

#ifndef _PRESTERA_ROUTER_HW_H_
#define _PRESTERA_ROUTER_HW_H_

struct prestera_vr {
        struct list_head router_node;
        refcount_t refcount;
        u32 tb_id;                      /* key (kernel fib table id) */
        u16 hw_vr_id;                   /* virtual router ID */
        u8 __pad[2];
};

struct prestera_rif_entry {
        struct prestera_rif_entry_key {
                struct prestera_iface iface;
        } key;
        struct prestera_vr *vr;
        unsigned char addr[ETH_ALEN];
        u16 hw_id; /* rif_id */
        struct list_head router_node; /* ht */
};

struct prestera_ip_addr {
        union {
                __be32 ipv4;
                struct in6_addr ipv6;
        } u;
        enum {
                PRESTERA_IPV4 = 0,
                PRESTERA_IPV6
        } v;
#define PRESTERA_IP_ADDR_PLEN(V) ((V) == PRESTERA_IPV4 ? 32 : \
                                  /* (V) == PRESTERA_IPV6 ? */ 128 /* : 0 */)
};

struct prestera_nh_neigh_key {
        struct prestera_ip_addr addr;
        /* Seems like rif is obsolete, because there is iface in info ?
         * Key can contain functional fields, or fields, which is used to
         * filter duplicate objects on logical level (before you pass it to
         * HW)... also key can be used to cover hardware restrictions.
         * In our case rif - is logical interface (even can be VLAN), which
         * is used in combination with IP address (which is also not related to
         * hardware nexthop) to provide logical compression of created nexthops.
         * You even can imagine, that rif+IPaddr is just cookie.
         */
        /* struct prestera_rif *rif; */
        /* Use just as cookie, to divide ARP domains (in order with addr) */
        void *rif;
};

/* Used for hw call */
struct prestera_neigh_info {
        struct prestera_iface iface;
        unsigned char ha[ETH_ALEN];
        u8 connected; /* bool. indicate, if mac/oif valid */
        u8 __pad[1];
};

/* Used to notify nh about neigh change */
struct prestera_nh_neigh {
        struct prestera_nh_neigh_key key;
        struct prestera_neigh_info info;
        struct rhash_head ht_node; /* node of prestera_vr */
        struct list_head nexthop_group_list;
};

#define PRESTERA_NHGR_SIZE_MAX 4

struct prestera_nexthop_group {
        struct prestera_nexthop_group_key {
                struct prestera_nh_neigh_key neigh[PRESTERA_NHGR_SIZE_MAX];
        } key;
        /* Store intermediate object here.
         * This prevent overhead kzalloc call.
         */
        /* nh_neigh is used only to notify nexthop_group */
        struct prestera_nh_neigh_head {
                struct prestera_nexthop_group *this;
                struct list_head head;
                /* ptr to neigh is not necessary.
                 * It used to prevent lookup of nh_neigh by key (n) on destroy
                 */
                struct prestera_nh_neigh *neigh;
        } nh_neigh_head[PRESTERA_NHGR_SIZE_MAX];
        struct rhash_head ht_node; /* node of prestera_vr */
        refcount_t refcount;
        u32 grp_id; /* hw */
};

struct prestera_fib_key {
        struct prestera_ip_addr addr;
        u32 prefix_len;
        u32 tb_id;
};

struct prestera_fib_info {
        struct prestera_vr *vr;
        struct list_head vr_node;
        enum prestera_fib_type {
                PRESTERA_FIB_TYPE_INVALID = 0,
                /* must be pointer to nh_grp id */
                PRESTERA_FIB_TYPE_UC_NH,
                /* It can be connected route
                 * and will be overlapped with neighbours
                 */
                PRESTERA_FIB_TYPE_TRAP,
                PRESTERA_FIB_TYPE_DROP
        } type;
        /* Valid only if type = UC_NH*/
        struct prestera_nexthop_group *nh_grp;
};

struct prestera_fib_node {
        struct rhash_head ht_node; /* node of prestera_vr */
        struct prestera_fib_key key;
        struct prestera_fib_info info; /* action related info */
};

struct prestera_rif_entry *
prestera_rif_entry_find(const struct prestera_switch *sw,
                        const struct prestera_rif_entry_key *k);
void prestera_rif_entry_destroy(struct prestera_switch *sw,
                                struct prestera_rif_entry *e);
struct prestera_rif_entry *
prestera_rif_entry_create(struct prestera_switch *sw,
                          struct prestera_rif_entry_key *k,
                          u32 tb_id, const unsigned char *addr);
struct prestera_nh_neigh *
prestera_nh_neigh_find(struct prestera_switch *sw,
                       struct prestera_nh_neigh_key *key);
struct prestera_nh_neigh *
prestera_nh_neigh_get(struct prestera_switch *sw,
                      struct prestera_nh_neigh_key *key);
void prestera_nh_neigh_put(struct prestera_switch *sw,
                           struct prestera_nh_neigh *neigh);
int prestera_nh_neigh_set(struct prestera_switch *sw,
                          struct prestera_nh_neigh *neigh);
bool prestera_nh_neigh_util_hw_state(struct prestera_switch *sw,
                                     struct prestera_nh_neigh *nh_neigh);
struct prestera_fib_node *prestera_fib_node_find(struct prestera_switch *sw,
                                                 struct prestera_fib_key *key);
void prestera_fib_node_destroy(struct prestera_switch *sw,
                               struct prestera_fib_node *fib_node);
struct prestera_fib_node *
prestera_fib_node_create(struct prestera_switch *sw,
                         struct prestera_fib_key *key,
                         enum prestera_fib_type fib_type,
                         struct prestera_nexthop_group_key *nh_grp_key);
int prestera_router_hw_init(struct prestera_switch *sw);
void prestera_router_hw_fini(struct prestera_switch *sw);

#endif /* _PRESTERA_ROUTER_HW_H_ */