提交 5ee38975 编写于 作者: D David S. Miller

Merge branch 'mlxsw-fib-offload'

Jiri Pirko says:

====================
mlxsw: Implement basic FIB offload and router interfaces

Introduce LPM trees management including virtual router management for HW.
Implement basic FIB offloading using switchdev FIB objects. For now only support
local routes and direct routes (next-hop support will be introduced in
a follow-up patchset).

Introduce router interfaces in patches 10-14.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -3,7 +3,7 @@
* Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015-2016 Ido Schimmel <idosch@mellanox.com>
* Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
* Copyright (c) 2015-2016 Jiri Pirko <jiri@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
......@@ -3454,6 +3454,436 @@ static inline void mlxsw_reg_ritr_pack(char *payload, bool enable,
mlxsw_reg_ritr_if_mac_memcpy_to(payload, mac);
}
/* RALTA - Router Algorithmic LPM Tree Allocation Register
* -------------------------------------------------------
* RALTA is used to allocate the LPM trees of the SHSPM method.
*/
#define MLXSW_REG_RALTA_ID 0x8010
#define MLXSW_REG_RALTA_LEN 0x04
static const struct mlxsw_reg_info mlxsw_reg_ralta = {
.id = MLXSW_REG_RALTA_ID,
.len = MLXSW_REG_RALTA_LEN,
};
/* reg_ralta_op
* opcode (valid for Write, must be 0 on Read)
* 0 - allocate a tree
* 1 - deallocate a tree
* Access: OP
*/
MLXSW_ITEM32(reg, ralta, op, 0x00, 28, 2);
enum mlxsw_reg_ralxx_protocol {
MLXSW_REG_RALXX_PROTOCOL_IPV4,
MLXSW_REG_RALXX_PROTOCOL_IPV6,
};
/* reg_ralta_protocol
* Protocol.
* Deallocation opcode: Reserved.
* Access: RW
*/
MLXSW_ITEM32(reg, ralta, protocol, 0x00, 24, 4);
/* reg_ralta_tree_id
* An identifier (numbered from 1..cap_shspm_max_trees-1) representing
* the tree identifier (managed by software).
* Note that tree_id 0 is allocated for a default-route tree.
* Access: Index
*/
MLXSW_ITEM32(reg, ralta, tree_id, 0x00, 0, 8);
static inline void mlxsw_reg_ralta_pack(char *payload, bool alloc,
enum mlxsw_reg_ralxx_protocol protocol,
u8 tree_id)
{
MLXSW_REG_ZERO(ralta, payload);
mlxsw_reg_ralta_op_set(payload, !alloc);
mlxsw_reg_ralta_protocol_set(payload, protocol);
mlxsw_reg_ralta_tree_id_set(payload, tree_id);
}
/* RALST - Router Algorithmic LPM Structure Tree Register
* ------------------------------------------------------
* RALST is used to set and query the structure of an LPM tree.
* The structure of the tree must be sorted as a sorted binary tree, while
* each node is a bin that is tagged as the length of the prefixes the lookup
* will refer to. Therefore, bin X refers to a set of entries with prefixes
* of X bits to match with the destination address. The bin 0 indicates
* the default action, when there is no match of any prefix.
*/
#define MLXSW_REG_RALST_ID 0x8011
#define MLXSW_REG_RALST_LEN 0x104
static const struct mlxsw_reg_info mlxsw_reg_ralst = {
.id = MLXSW_REG_RALST_ID,
.len = MLXSW_REG_RALST_LEN,
};
/* reg_ralst_root_bin
* The bin number of the root bin.
* 0<root_bin=<(length of IP address)
* For a default-route tree configure 0xff
* Access: RW
*/
MLXSW_ITEM32(reg, ralst, root_bin, 0x00, 16, 8);
/* reg_ralst_tree_id
* Tree identifier numbered from 1..(cap_shspm_max_trees-1).
* Access: Index
*/
MLXSW_ITEM32(reg, ralst, tree_id, 0x00, 0, 8);
#define MLXSW_REG_RALST_BIN_NO_CHILD 0xff
#define MLXSW_REG_RALST_BIN_OFFSET 0x04
#define MLXSW_REG_RALST_BIN_COUNT 128
/* reg_ralst_left_child_bin
* Holding the children of the bin according to the stored tree's structure.
* For trees composed of less than 4 blocks, the bins in excess are reserved.
* Note that tree_id 0 is allocated for a default-route tree, bins are 0xff
* Access: RW
*/
MLXSW_ITEM16_INDEXED(reg, ralst, left_child_bin, 0x04, 8, 8, 0x02, 0x00, false);
/* reg_ralst_right_child_bin
* Holding the children of the bin according to the stored tree's structure.
* For trees composed of less than 4 blocks, the bins in excess are reserved.
* Note that tree_id 0 is allocated for a default-route tree, bins are 0xff
* Access: RW
*/
MLXSW_ITEM16_INDEXED(reg, ralst, right_child_bin, 0x04, 0, 8, 0x02, 0x00,
false);
static inline void mlxsw_reg_ralst_pack(char *payload, u8 root_bin, u8 tree_id)
{
MLXSW_REG_ZERO(ralst, payload);
/* Initialize all bins to have no left or right child */
memset(payload + MLXSW_REG_RALST_BIN_OFFSET,
MLXSW_REG_RALST_BIN_NO_CHILD, MLXSW_REG_RALST_BIN_COUNT * 2);
mlxsw_reg_ralst_root_bin_set(payload, root_bin);
mlxsw_reg_ralst_tree_id_set(payload, tree_id);
}
static inline void mlxsw_reg_ralst_bin_pack(char *payload, u8 bin_number,
u8 left_child_bin,
u8 right_child_bin)
{
int bin_index = bin_number - 1;
mlxsw_reg_ralst_left_child_bin_set(payload, bin_index, left_child_bin);
mlxsw_reg_ralst_right_child_bin_set(payload, bin_index,
right_child_bin);
}
/* RALTB - Router Algorithmic LPM Tree Binding Register
* ----------------------------------------------------
* RALTB is used to bind virtual router and protocol to an allocated LPM tree.
*/
#define MLXSW_REG_RALTB_ID 0x8012
#define MLXSW_REG_RALTB_LEN 0x04
static const struct mlxsw_reg_info mlxsw_reg_raltb = {
.id = MLXSW_REG_RALTB_ID,
.len = MLXSW_REG_RALTB_LEN,
};
/* reg_raltb_virtual_router
* Virtual Router ID
* Range is 0..cap_max_virtual_routers-1
* Access: Index
*/
MLXSW_ITEM32(reg, raltb, virtual_router, 0x00, 16, 16);
/* reg_raltb_protocol
* Protocol.
* Access: Index
*/
MLXSW_ITEM32(reg, raltb, protocol, 0x00, 12, 4);
/* reg_raltb_tree_id
* Tree to be used for the {virtual_router, protocol}
* Tree identifier numbered from 1..(cap_shspm_max_trees-1).
* By default, all Unicast IPv4 and IPv6 are bound to tree_id 0.
* Access: RW
*/
MLXSW_ITEM32(reg, raltb, tree_id, 0x00, 0, 8);
static inline void mlxsw_reg_raltb_pack(char *payload, u16 virtual_router,
enum mlxsw_reg_ralxx_protocol protocol,
u8 tree_id)
{
MLXSW_REG_ZERO(raltb, payload);
mlxsw_reg_raltb_virtual_router_set(payload, virtual_router);
mlxsw_reg_raltb_protocol_set(payload, protocol);
mlxsw_reg_raltb_tree_id_set(payload, tree_id);
}
/* RALUE - Router Algorithmic LPM Unicast Entry Register
* -----------------------------------------------------
* RALUE is used to configure and query LPM entries that serve
* the Unicast protocols.
*/
#define MLXSW_REG_RALUE_ID 0x8013
#define MLXSW_REG_RALUE_LEN 0x38
static const struct mlxsw_reg_info mlxsw_reg_ralue = {
.id = MLXSW_REG_RALUE_ID,
.len = MLXSW_REG_RALUE_LEN,
};
/* reg_ralue_protocol
* Protocol.
* Access: Index
*/
MLXSW_ITEM32(reg, ralue, protocol, 0x00, 24, 4);
enum mlxsw_reg_ralue_op {
/* Read operation. If entry doesn't exist, the operation fails. */
MLXSW_REG_RALUE_OP_QUERY_READ = 0,
/* Clear on read operation. Used to read entry and
* clear Activity bit.
*/
MLXSW_REG_RALUE_OP_QUERY_CLEAR = 1,
/* Write operation. Used to write a new entry to the table. All RW
* fields are written for new entry. Activity bit is set
* for new entries.
*/
MLXSW_REG_RALUE_OP_WRITE_WRITE = 0,
/* Update operation. Used to update an existing route entry and
* only update the RW fields that are detailed in the field
* op_u_mask. If entry doesn't exist, the operation fails.
*/
MLXSW_REG_RALUE_OP_WRITE_UPDATE = 1,
/* Clear activity. The Activity bit (the field a) is cleared
* for the entry.
*/
MLXSW_REG_RALUE_OP_WRITE_CLEAR = 2,
/* Delete operation. Used to delete an existing entry. If entry
* doesn't exist, the operation fails.
*/
MLXSW_REG_RALUE_OP_WRITE_DELETE = 3,
};
/* reg_ralue_op
* Operation.
* Access: OP
*/
MLXSW_ITEM32(reg, ralue, op, 0x00, 20, 3);
/* reg_ralue_a
* Activity. Set for new entries. Set if a packet lookup has hit on the
* specific entry, only if the entry is a route. To clear the a bit, use
* "clear activity" op.
* Enabled by activity_dis in RGCR
* Access: RO
*/
MLXSW_ITEM32(reg, ralue, a, 0x00, 16, 1);
/* reg_ralue_virtual_router
* Virtual Router ID
* Range is 0..cap_max_virtual_routers-1
* Access: Index
*/
MLXSW_ITEM32(reg, ralue, virtual_router, 0x04, 16, 16);
#define MLXSW_REG_RALUE_OP_U_MASK_ENTRY_TYPE BIT(0)
#define MLXSW_REG_RALUE_OP_U_MASK_BMP_LEN BIT(1)
#define MLXSW_REG_RALUE_OP_U_MASK_ACTION BIT(2)
/* reg_ralue_op_u_mask
* opcode update mask.
* On read operation, this field is reserved.
* This field is valid for update opcode, otherwise - reserved.
* This field is a bitmask of the fields that should be updated.
* Access: WO
*/
MLXSW_ITEM32(reg, ralue, op_u_mask, 0x04, 8, 3);
/* reg_ralue_prefix_len
* Number of bits in the prefix of the LPM route.
* Note that for IPv6 prefixes, if prefix_len>64 the entry consumes
* two entries in the physical HW table.
* Access: Index
*/
MLXSW_ITEM32(reg, ralue, prefix_len, 0x08, 0, 8);
/* reg_ralue_dip*
* The prefix of the route or of the marker that the object of the LPM
* is compared with. The most significant bits of the dip are the prefix.
* The list significant bits must be '0' if the prefix_len is smaller
* than 128 for IPv6 or smaller than 32 for IPv4.
* IPv4 address uses bits dip[31:0] and bits dip[127:32] are reserved.
* Access: Index
*/
MLXSW_ITEM32(reg, ralue, dip4, 0x18, 0, 32);
enum mlxsw_reg_ralue_entry_type {
MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_ENTRY = 1,
MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY = 2,
MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_AND_ROUTE_ENTRY = 3,
};
/* reg_ralue_entry_type
* Entry type.
* Note - for Marker entries, the action_type and action fields are reserved.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, entry_type, 0x1C, 30, 2);
/* reg_ralue_bmp_len
* The best match prefix length in the case that there is no match for
* longer prefixes.
* If (entry_type != MARKER_ENTRY), bmp_len must be equal to prefix_len
* Note for any update operation with entry_type modification this
* field must be set.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, bmp_len, 0x1C, 16, 8);
enum mlxsw_reg_ralue_action_type {
MLXSW_REG_RALUE_ACTION_TYPE_REMOTE,
MLXSW_REG_RALUE_ACTION_TYPE_LOCAL,
MLXSW_REG_RALUE_ACTION_TYPE_IP2ME,
};
/* reg_ralue_action_type
* Action Type
* Indicates how the IP address is connected.
* It can be connected to a local subnet through local_erif or can be
* on a remote subnet connected through a next-hop router,
* or transmitted to the CPU.
* Reserved when entry_type = MARKER_ENTRY
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, action_type, 0x1C, 0, 2);
enum mlxsw_reg_ralue_trap_action {
MLXSW_REG_RALUE_TRAP_ACTION_NOP,
MLXSW_REG_RALUE_TRAP_ACTION_TRAP,
MLXSW_REG_RALUE_TRAP_ACTION_MIRROR_TO_CPU,
MLXSW_REG_RALUE_TRAP_ACTION_MIRROR,
MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR,
};
/* reg_ralue_trap_action
* Trap action.
* For IP2ME action, only NOP and MIRROR are possible.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, trap_action, 0x20, 28, 4);
/* reg_ralue_trap_id
* Trap ID to be reported to CPU.
* Trap ID is RTR_INGRESS0 or RTR_INGRESS1.
* For trap_action of NOP, MIRROR and DISCARD_ERROR, trap_id is reserved.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, trap_id, 0x20, 0, 9);
/* reg_ralue_adjacency_index
* Points to the first entry of the group-based ECMP.
* Only relevant in case of REMOTE action.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, adjacency_index, 0x24, 0, 24);
/* reg_ralue_ecmp_size
* Amount of sequential entries starting
* from the adjacency_index (the number of ECMPs).
* The valid range is 1-64, 512, 1024, 2048 and 4096.
* Reserved when trap_action is TRAP or DISCARD_ERROR.
* Only relevant in case of REMOTE action.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, ecmp_size, 0x28, 0, 13);
/* reg_ralue_local_erif
* Egress Router Interface.
* Only relevant in case of LOCAL action.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, local_erif, 0x24, 0, 16);
/* reg_ralue_v
* Valid bit for the tunnel_ptr field.
* If valid = 0 then trap to CPU as IP2ME trap ID.
* If valid = 1 and the packet format allows NVE or IPinIP tunnel
* decapsulation then tunnel decapsulation is done.
* If valid = 1 and packet format does not allow NVE or IPinIP tunnel
* decapsulation then trap as IP2ME trap ID.
* Only relevant in case of IP2ME action.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, v, 0x24, 31, 1);
/* reg_ralue_tunnel_ptr
* Tunnel Pointer for NVE or IPinIP tunnel decapsulation.
* For Spectrum, pointer to KVD Linear.
* Only relevant in case of IP2ME action.
* Access: RW
*/
MLXSW_ITEM32(reg, ralue, tunnel_ptr, 0x24, 0, 24);
static inline void mlxsw_reg_ralue_pack(char *payload,
enum mlxsw_reg_ralxx_protocol protocol,
enum mlxsw_reg_ralue_op op,
u16 virtual_router, u8 prefix_len)
{
MLXSW_REG_ZERO(ralue, payload);
mlxsw_reg_ralue_protocol_set(payload, protocol);
mlxsw_reg_ralue_virtual_router_set(payload, virtual_router);
mlxsw_reg_ralue_prefix_len_set(payload, prefix_len);
mlxsw_reg_ralue_entry_type_set(payload,
MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY);
mlxsw_reg_ralue_bmp_len_set(payload, prefix_len);
}
static inline void mlxsw_reg_ralue_pack4(char *payload,
enum mlxsw_reg_ralxx_protocol protocol,
enum mlxsw_reg_ralue_op op,
u16 virtual_router, u8 prefix_len,
u32 dip)
{
mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len);
mlxsw_reg_ralue_dip4_set(payload, dip);
}
static inline void
mlxsw_reg_ralue_act_remote_pack(char *payload,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u32 adjacency_index, u16 ecmp_size)
{
mlxsw_reg_ralue_action_type_set(payload,
MLXSW_REG_RALUE_ACTION_TYPE_REMOTE);
mlxsw_reg_ralue_trap_action_set(payload, trap_action);
mlxsw_reg_ralue_trap_id_set(payload, trap_id);
mlxsw_reg_ralue_adjacency_index_set(payload, adjacency_index);
mlxsw_reg_ralue_ecmp_size_set(payload, ecmp_size);
}
static inline void
mlxsw_reg_ralue_act_local_pack(char *payload,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u16 local_erif)
{
mlxsw_reg_ralue_action_type_set(payload,
MLXSW_REG_RALUE_ACTION_TYPE_LOCAL);
mlxsw_reg_ralue_trap_action_set(payload, trap_action);
mlxsw_reg_ralue_trap_id_set(payload, trap_id);
mlxsw_reg_ralue_local_erif_set(payload, local_erif);
}
static inline void
mlxsw_reg_ralue_act_ip2me_pack(char *payload)
{
mlxsw_reg_ralue_action_type_set(payload,
MLXSW_REG_RALUE_ACTION_TYPE_IP2ME);
}
/* MFCR - Management Fan Control Register
* --------------------------------------
* This register controls the settings of the Fan Speed PWM mechanism.
......@@ -4196,6 +4626,14 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
return "RGCR";
case MLXSW_REG_RITR_ID:
return "RITR";
case MLXSW_REG_RALTA_ID:
return "RALTA";
case MLXSW_REG_RALST_ID:
return "RALST";
case MLXSW_REG_RALTB_ID:
return "RALTB";
case MLXSW_REG_RALUE_ID:
return "RALUE";
case MLXSW_REG_MFCR_ID:
return "MFCR";
case MLXSW_REG_MFSC_ID:
......
......@@ -43,15 +43,17 @@
#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/dcbnl.h>
#include <linux/in6.h>
#include <net/switchdev.h>
#include "port.h"
#include "core.h"
#define MLXSW_SP_VFID_BASE VLAN_N_VID
#define MLXSW_SP_VFID_PORT_MAX 512 /* Non-bridged VLAN interfaces */
#define MLXSW_SP_VFID_BR_MAX 6144 /* Bridged VLAN interfaces */
#define MLXSW_SP_VFID_MAX (MLXSW_SP_VFID_PORT_MAX + MLXSW_SP_VFID_BR_MAX)
#define MLXSW_SP_VFID_MAX 6656 /* Bridged VLAN interfaces */
#define MLXSW_SP_RFID_BASE 15360
#define MLXSW_SP_RIF_MAX 800
#define MLXSW_SP_LAG_MAX 64
#define MLXSW_SP_PORT_PER_LAG_MAX 16
......@@ -60,6 +62,12 @@
#define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4
#define MLXSW_SP_LPM_TREE_MIN 2 /* trees 0 and 1 are reserved */
#define MLXSW_SP_LPM_TREE_MAX 22
#define MLXSW_SP_LPM_TREE_COUNT (MLXSW_SP_LPM_TREE_MAX - MLXSW_SP_LPM_TREE_MIN)
#define MLXSW_SP_VIRTUAL_ROUTER_MAX 256
#define MLXSW_SP_PORT_BASE_SPEED 25000 /* Mb/s */
#define MLXSW_SP_BYTES_PER_CELL 96
......@@ -74,8 +82,6 @@
#define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */
#define MLXSW_SP_RIF_MAX 800
static inline u16 mlxsw_sp_pfc_delay_get(int mtu, u16 delay)
{
delay = MLXSW_SP_BYTES_TO_CELLS(DIV_ROUND_UP(delay, BITS_PER_BYTE));
......@@ -94,12 +100,16 @@ struct mlxsw_sp_fid {
struct list_head list;
unsigned int ref_count;
struct net_device *dev;
struct mlxsw_sp_rif *r;
u16 fid;
u16 vid;
};
struct mlxsw_sp_rif {
struct net_device *dev;
unsigned int ref_count;
struct mlxsw_sp_fid *f;
unsigned char addr[ETH_ALEN];
int mtu;
u16 rif;
};
......@@ -123,7 +133,17 @@ static inline u16 mlxsw_sp_fid_to_vfid(u16 fid)
static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
{
return fid >= MLXSW_SP_VFID_BASE;
return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_RFID_BASE;
}
static inline bool mlxsw_sp_fid_is_rfid(u16 fid)
{
return fid >= MLXSW_SP_RFID_BASE;
}
static inline u16 mlxsw_sp_rif_sp_to_fid(u16 rif)
{
return MLXSW_SP_RFID_BASE + rif;
}
struct mlxsw_sp_sb_pr {
......@@ -160,15 +180,45 @@ struct mlxsw_sp_sb {
} ports[MLXSW_PORT_MAX_PORTS];
};
#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
struct mlxsw_sp_prefix_usage {
DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
};
enum mlxsw_sp_l3proto {
MLXSW_SP_L3_PROTO_IPV4,
MLXSW_SP_L3_PROTO_IPV6,
};
struct mlxsw_sp_lpm_tree {
u8 id; /* tree ID */
unsigned int ref_count;
enum mlxsw_sp_l3proto proto;
struct mlxsw_sp_prefix_usage prefix_usage;
};
struct mlxsw_sp_fib;
struct mlxsw_sp_vr {
u16 id; /* virtual router ID */
bool used;
enum mlxsw_sp_l3proto proto;
u32 tb_id; /* kernel fib table id */
struct mlxsw_sp_lpm_tree *lpm_tree;
struct mlxsw_sp_fib *fib;
};
struct mlxsw_sp_router {
struct mlxsw_sp_lpm_tree lpm_trees[MLXSW_SP_LPM_TREE_COUNT];
struct mlxsw_sp_vr vrs[MLXSW_SP_VIRTUAL_ROUTER_MAX];
};
struct mlxsw_sp {
struct {
struct list_head list;
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_PORT_MAX);
} port_vfids;
struct {
struct list_head list;
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_BR_MAX);
} br_vfids;
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX);
} vfids;
struct {
struct list_head list;
DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX);
......@@ -192,6 +242,7 @@ struct mlxsw_sp {
struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX];
u8 port_to_module[MLXSW_PORT_MAX_PORTS];
struct mlxsw_sp_sb sb;
struct mlxsw_sp_router router;
};
static inline struct mlxsw_sp_upper *
......@@ -250,6 +301,9 @@ struct mlxsw_sp_port {
struct list_head vports_list;
};
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
static inline bool
mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
{
......@@ -295,7 +349,7 @@ mlxsw_sp_vport_fid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
}
static inline struct net_device *
mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
mlxsw_sp_vport_dev_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
{
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
......@@ -333,6 +387,31 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
return NULL;
}
static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
u16 fid)
{
struct mlxsw_sp_fid *f;
list_for_each_entry(f, &mlxsw_sp->fids, list)
if (f->fid == fid)
return f;
return NULL;
}
static inline struct mlxsw_sp_fid *
mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev)
{
struct mlxsw_sp_fid *f;
list_for_each_entry(f, &mlxsw_sp->vfids.list, list)
if (f->dev == br_dev)
return f;
return NULL;
}
static inline struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev)
......@@ -403,6 +482,12 @@ int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid);
int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
bool adding);
struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid);
void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f);
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *r);
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
bool dwrr, u8 dwrr_weight);
......@@ -434,5 +519,10 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
const struct switchdev_obj_ipv4_fib *fib4,
struct switchdev_trans *trans);
int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
const struct switchdev_obj_ipv4_fib *fib4);
#endif
......@@ -166,11 +166,6 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
}
static bool mlxsw_sp_vfid_is_vport_br(u16 vfid)
{
return vfid >= MLXSW_SP_VFID_PORT_MAX;
}
static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
u16 idx_begin, u16 idx_end, bool set,
bool only_uc)
......@@ -182,15 +177,10 @@ static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
char *sftr_pl;
int err;
if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
if (mlxsw_sp_port_is_vport(mlxsw_sp_port))
table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID;
if (mlxsw_sp_vfid_is_vport_br(idx_begin))
local_port = mlxsw_sp_port->local_port;
else
local_port = MLXSW_PORT_CPU_PORT;
} else {
else
table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
}
sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
if (!sftr_pl)
......@@ -384,18 +374,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
return err;
}
static struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
u16 fid)
{
struct mlxsw_sp_fid *f;
list_for_each_entry(f, &mlxsw_sp->fids, list)
if (f->fid == fid)
return f;
return NULL;
}
static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create)
{
char sfmr_pl[MLXSW_REG_SFMR_LEN];
......@@ -426,8 +404,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_alloc(u16 fid)
return f;
}
static struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
u16 fid)
struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
{
struct mlxsw_sp_fid *f;
int err;
......@@ -462,13 +439,15 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
return ERR_PTR(err);
}
static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fid *f)
void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f)
{
u16 fid = f->fid;
list_del(&f->list);
if (f->r)
mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->r);
kfree(f);
mlxsw_sp_fid_op(mlxsw_sp, fid, false);
......@@ -753,9 +732,10 @@ static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
MLXSW_REG_SFD_OP_WRITE_REMOVE;
}
static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const char *mac, u16 fid, bool adding,
bool dynamic)
static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const char *mac, u16 fid, bool adding,
enum mlxsw_reg_sfd_rec_action action,
bool dynamic)
{
char *sfd_pl;
int err;
......@@ -766,14 +746,29 @@ static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
local_port);
mac, fid, action, local_port);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
kfree(sfd_pl);
return err;
}
static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const char *mac, u16 fid, bool adding,
bool dynamic)
{
return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
MLXSW_REG_SFD_REC_ACTION_NOP, dynamic);
}
int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
bool adding)
{
return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
false);
}
static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
const char *mac, u16 fid, u16 lag_vid,
bool adding, bool dynamic)
......@@ -978,6 +973,11 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev,
SWITCHDEV_OBJ_PORT_VLAN(obj),
trans);
break;
case SWITCHDEV_OBJ_ID_IPV4_FIB:
err = mlxsw_sp_router_fib4_add(mlxsw_sp_port,
SWITCHDEV_OBJ_IPV4_FIB(obj),
trans);
break;
case SWITCHDEV_OBJ_ID_PORT_FDB:
err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port,
SWITCHDEV_OBJ_PORT_FDB(obj),
......@@ -1123,6 +1123,10 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev,
err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
SWITCHDEV_OBJ_PORT_VLAN(obj));
break;
case SWITCHDEV_OBJ_ID_IPV4_FIB:
err = mlxsw_sp_router_fib4_del(mlxsw_sp_port,
SWITCHDEV_OBJ_IPV4_FIB(obj));
break;
case SWITCHDEV_OBJ_ID_PORT_FDB:
err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port,
SWITCHDEV_OBJ_PORT_FDB(obj));
......
......@@ -3804,12 +3804,30 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
void *netdev_lower_get_next(struct net_device *dev,
struct list_head **iter);
#define netdev_for_each_lower_dev(dev, ldev, iter) \
for (iter = (dev)->adj_list.lower.next, \
ldev = netdev_lower_get_next(dev, &(iter)); \
ldev; \
ldev = netdev_lower_get_next(dev, &(iter)))
struct net_device *netdev_all_lower_get_next(struct net_device *dev,
struct list_head **iter);
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter);
#define netdev_for_each_all_lower_dev(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next(dev, &(iter)))
#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)))
void *netdev_adjacent_get_private(struct list_head *adj_list);
void *netdev_lower_get_first_private_rcu(struct net_device *dev);
struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
......
......@@ -5444,6 +5444,52 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter)
}
EXPORT_SYMBOL(netdev_lower_get_next);
/**
* netdev_all_lower_get_next - Get the next device from all lower neighbour list
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RTNL lock or
* its own locking that guarantees that the neighbour all lower
* list will remain unchanged.
*/
struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter)
{
struct netdev_adjacent *lower;
lower = list_entry(*iter, struct netdev_adjacent, list);
if (&lower->list == &dev->all_adj_list.lower)
return NULL;
*iter = lower->list.next;
return lower->dev;
}
EXPORT_SYMBOL(netdev_all_lower_get_next);
/**
* netdev_all_lower_get_next_rcu - Get the next device from all
* lower neighbour list, RCU variant
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RCU read lock.
*/
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter)
{
struct netdev_adjacent *lower;
lower = list_first_or_null_rcu(&dev->all_adj_list.lower,
struct netdev_adjacent, list);
return lower ? lower->dev : NULL;
}
EXPORT_SYMBOL(netdev_all_lower_get_next_rcu);
/**
* netdev_lower_get_first_private_rcu - Get the first ->private from the
* lower neighbour list, RCU
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册