mirror of https://gitee.com/openkylin/linux.git
rocker: add ndo_bridge_setlink/getlink support for learning policy
Rocker ports will use new "swdev" hwmode for bridge port offload policy. Current supported policy settings are BR_LEARNING and BR_LEARNING_SYNC. User can turn on/off device port FDB learning and syncing to bridge. Signed-off-by: Scott Feldman <sfeldma@gmail.com> Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ce76ca689d
commit
5111f80cbc
|
@ -203,6 +203,7 @@ struct rocker_port {
|
|||
u32 lport;
|
||||
__be16 internal_vlan_id;
|
||||
int stp_state;
|
||||
u32 brport_flags;
|
||||
bool ctrls[ROCKER_CTRL_MAX];
|
||||
unsigned long vlan_bitmap[ROCKER_VLAN_BITMAP_LEN];
|
||||
struct napi_struct napi_tx;
|
||||
|
@ -1629,6 +1630,30 @@ rocker_cmd_set_port_settings_macaddr_prep(struct rocker *rocker,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rocker_cmd_set_port_learning_prep(struct rocker *rocker,
|
||||
struct rocker_port *rocker_port,
|
||||
struct rocker_desc_info *desc_info,
|
||||
void *priv)
|
||||
{
|
||||
struct rocker_tlv *cmd_info;
|
||||
|
||||
if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
|
||||
ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
|
||||
return -EMSGSIZE;
|
||||
cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
|
||||
if (!cmd_info)
|
||||
return -EMSGSIZE;
|
||||
if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_LPORT,
|
||||
rocker_port->lport))
|
||||
return -EMSGSIZE;
|
||||
if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
|
||||
!!(rocker_port->brport_flags & BR_LEARNING)))
|
||||
return -EMSGSIZE;
|
||||
rocker_tlv_nest_end(desc_info, cmd_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
|
||||
struct ethtool_cmd *ecmd)
|
||||
{
|
||||
|
@ -1663,6 +1688,13 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
|
|||
macaddr, NULL, NULL, false);
|
||||
}
|
||||
|
||||
static int rocker_port_set_learning(struct rocker_port *rocker_port)
|
||||
{
|
||||
return rocker_cmd_exec(rocker_port->rocker, rocker_port,
|
||||
rocker_cmd_set_port_learning_prep,
|
||||
NULL, NULL, NULL, false);
|
||||
}
|
||||
|
||||
static int rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
|
||||
struct rocker_flow_tbl_entry *entry)
|
||||
{
|
||||
|
@ -2995,6 +3027,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
|
|||
u32 out_lport = rocker_port->lport;
|
||||
u32 tunnel_id = 0;
|
||||
u32 group_id = ROCKER_GROUP_NONE;
|
||||
bool syncing = !!(rocker_port->brport_flags & BR_LEARNING_SYNC);
|
||||
bool copy_to_cpu = false;
|
||||
int err;
|
||||
|
||||
|
@ -3009,6 +3042,9 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!syncing)
|
||||
return 0;
|
||||
|
||||
if (!rocker_port_is_bridged(rocker_port))
|
||||
return 0;
|
||||
|
||||
|
@ -3659,6 +3695,64 @@ static int rocker_port_fdb_dump(struct sk_buff *skb,
|
|||
return idx;
|
||||
}
|
||||
|
||||
static int rocker_port_bridge_setlink(struct net_device *dev,
|
||||
struct nlmsghdr *nlh)
|
||||
{
|
||||
struct rocker_port *rocker_port = netdev_priv(dev);
|
||||
struct nlattr *protinfo;
|
||||
struct nlattr *afspec;
|
||||
struct nlattr *attr;
|
||||
u16 mode;
|
||||
int err;
|
||||
|
||||
protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
|
||||
IFLA_PROTINFO);
|
||||
afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
|
||||
|
||||
if (afspec) {
|
||||
attr = nla_find_nested(afspec, IFLA_BRIDGE_MODE);
|
||||
if (attr) {
|
||||
mode = nla_get_u16(attr);
|
||||
if (mode != BRIDGE_MODE_SWDEV)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (protinfo) {
|
||||
attr = nla_find_nested(protinfo, IFLA_BRPORT_LEARNING);
|
||||
if (attr) {
|
||||
if (nla_get_u8(attr))
|
||||
rocker_port->brport_flags |= BR_LEARNING;
|
||||
else
|
||||
rocker_port->brport_flags &= ~BR_LEARNING;
|
||||
err = rocker_port_set_learning(rocker_port);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
attr = nla_find_nested(protinfo, IFLA_BRPORT_LEARNING_SYNC);
|
||||
if (attr) {
|
||||
if (nla_get_u8(attr))
|
||||
rocker_port->brport_flags |= BR_LEARNING_SYNC;
|
||||
else
|
||||
rocker_port->brport_flags &= ~BR_LEARNING_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rocker_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
|
||||
struct net_device *dev,
|
||||
u32 filter_mask)
|
||||
{
|
||||
struct rocker_port *rocker_port = netdev_priv(dev);
|
||||
u16 mode = BRIDGE_MODE_SWDEV;
|
||||
u32 mask = BR_LEARNING | BR_LEARNING_SYNC;
|
||||
|
||||
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode,
|
||||
rocker_port->brport_flags, mask);
|
||||
}
|
||||
|
||||
static int rocker_port_switch_parent_id_get(struct net_device *dev,
|
||||
struct netdev_phys_item_id *psid)
|
||||
{
|
||||
|
@ -3687,6 +3781,8 @@ static const struct net_device_ops rocker_port_netdev_ops = {
|
|||
.ndo_fdb_add = rocker_port_fdb_add,
|
||||
.ndo_fdb_del = rocker_port_fdb_del,
|
||||
.ndo_fdb_dump = rocker_port_fdb_dump,
|
||||
.ndo_bridge_setlink = rocker_port_bridge_setlink,
|
||||
.ndo_bridge_getlink = rocker_port_bridge_getlink,
|
||||
.ndo_switch_parent_id_get = rocker_port_switch_parent_id_get,
|
||||
.ndo_switch_port_stp_update = rocker_port_switch_port_stp_update,
|
||||
};
|
||||
|
@ -3887,6 +3983,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
|||
rocker_port->rocker = rocker;
|
||||
rocker_port->port_number = port_number;
|
||||
rocker_port->lport = port_number + 1;
|
||||
rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
|
||||
|
||||
rocker_port_dev_addr_init(rocker, rocker_port);
|
||||
dev->netdev_ops = &rocker_port_netdev_ops;
|
||||
|
@ -3906,6 +4003,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
|||
}
|
||||
rocker->ports[port_number] = rocker_port;
|
||||
|
||||
rocker_port_set_learning(rocker_port);
|
||||
|
||||
rocker_port->internal_vlan_id =
|
||||
rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
|
||||
err = rocker_port_ig_tbl(rocker_port, 0);
|
||||
|
|
|
@ -139,6 +139,7 @@ enum {
|
|||
ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, /* u8 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */
|
||||
|
||||
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
|
||||
ROCKER_TLV_CMD_PORT_SETTINGS_MAX =
|
||||
|
|
Loading…
Reference in New Issue