diff mbox

[net-next,v3,17/17] rocker: add ndo_bridge_setlnk/getlink support for learning policy

Message ID 1416911328-10979-18-git-send-email-jiri@resnulli.us
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Jiri Pirko Nov. 25, 2014, 10:28 a.m. UTC
From: Scott Feldman <sfeldma@gmail.com>

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>
---
new in v3
---
 drivers/net/ethernet/rocker/rocker.c | 99 ++++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h |  1 +
 2 files changed, 100 insertions(+)

Comments

Jamal Hadi Salim Nov. 25, 2014, 4:09 p.m. UTC | #1
On 11/25/14 05:28, Jiri Pirko wrote:
> From: Scott Feldman <sfeldma@gmail.com>
>
> 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>

as previous comments - please submit rocker separately

cheers,
jamal
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Scott Feldman Nov. 25, 2014, 6:55 p.m. UTC | #2
On Tue, Nov 25, 2014 at 6:09 AM, Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> On 11/25/14 05:28, Jiri Pirko wrote:
>>
>> From: Scott Feldman <sfeldma@gmail.com>
>>
>> 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>
>
>
> as previous comments - please submit rocker separately

I disagree.  API changes need a reference implementation to show usage
and for testing.  If you have have an alternate switch implementation
that achieves the same goal, bring it forward.

> cheers,
> jamal
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jamal Hadi Salim Nov. 25, 2014, 7 p.m. UTC | #3
On 11/25/14 13:55, Scott Feldman wrote:

> I disagree.  API changes need a reference implementation to show usage
> and for testing.  If you have have an alternate switch implementation
> that achieves the same goal, bring it forward.
>

Yes, point conceded ;->

/me waits for the next guy who is going to smirk at me for saying the
above and tell Jiri to fix his typo ;->


cheers,
jamal

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko Nov. 25, 2014, 8:42 p.m. UTC | #4
Tue, Nov 25, 2014 at 08:00:33PM CET, jhs@mojatatu.com wrote:
>On 11/25/14 13:55, Scott Feldman wrote:
>
>>I disagree.  API changes need a reference implementation to show usage
>>and for testing.  If you have have an alternate switch implementation
>>that achieves the same goal, bring it forward.
>>
>
>Yes, point conceded ;->
>
>/me waits for the next guy who is going to smirk at me for saying the
>above and tell Jiri to fix his typo ;->

Yep, people do not read replies :)
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Graf Nov. 26, 2014, 11:07 a.m. UTC | #5
On 11/25/14 at 11:28am, Jiri Pirko wrote:
> @@ -3657,6 +3693,64 @@ skip:
>  	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;
> +		}
> +	}

The Netlink message is completely unverified at this point. All
rtnl_bridge_setlink() does is verify that msgsize >= ifinfomsg.
All of the drivers but br_setlink() need fixing in this regard.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko Nov. 26, 2014, 11:27 a.m. UTC | #6
Wed, Nov 26, 2014 at 12:07:09PM CET, tgraf@suug.ch wrote:
>On 11/25/14 at 11:28am, Jiri Pirko wrote:
>> @@ -3657,6 +3693,64 @@ skip:
>>  	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;
>> +		}
>> +	}
>
>The Netlink message is completely unverified at this point. All
>rtnl_bridge_setlink() does is verify that msgsize >= ifinfomsg.
>All of the drivers but br_setlink() need fixing in this regard.

I believe that we should fix this for all drivers in a follow-up patch.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Graf Nov. 26, 2014, 11:30 a.m. UTC | #7
On 11/26/14 at 12:27pm, Jiri Pirko wrote:
> Wed, Nov 26, 2014 at 12:07:09PM CET, tgraf@suug.ch wrote:
> >The Netlink message is completely unverified at this point. All
> >rtnl_bridge_setlink() does is verify that msgsize >= ifinfomsg.
> >All of the drivers but br_setlink() need fixing in this regard.
> 
> I believe that we should fix this for all drivers in a follow-up patch.

I'm working on this. Will send fixes later today.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko Nov. 26, 2014, 11:42 a.m. UTC | #8
Wed, Nov 26, 2014 at 12:30:24PM CET, tgraf@suug.ch wrote:
>On 11/26/14 at 12:27pm, Jiri Pirko wrote:
>> Wed, Nov 26, 2014 at 12:07:09PM CET, tgraf@suug.ch wrote:
>> >The Netlink message is completely unverified at this point. All
>> >rtnl_bridge_setlink() does is verify that msgsize >= ifinfomsg.
>> >All of the drivers but br_setlink() need fixing in this regard.
>> 
>> I believe that we should fix this for all drivers in a follow-up patch.
>
>I'm working on this. Will send fixes later today.


Feel free to fix rocker as well. I'll take your patch into my queue.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 1434497..6d56960 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -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;
 
@@ -3657,6 +3693,64 @@  skip:
 	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)
 {
@@ -3685,6 +3779,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,
 };
@@ -3885,6 +3981,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;
@@ -3904,6 +4001,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);
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 5251cf8..8d2865b 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -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 =