Netdev List
 help / color / mirror / Atom feed
* [RFC PATCH net-next 5/5] bridge: vlan lwt dst_metadata hooks in ingress and egress paths
From: Roopa Prabhu @ 2017-01-21  5:46 UTC (permalink / raw)
  To: netdev; +Cc: davem, stephen, nikolay, tgraf, hannes, jbenc, pshelar, dsa, hadi
In-Reply-To: <1484977616-1541-1-git-send-email-roopa@cumulusnetworks.com>

From: Roopa Prabhu <roopa@cumulusnetworks.com>

- ingress hook:
    - if port is a lwt tunnel port, use tunnel info in
      attached dst_metadata to map it to a local vlan
- egress hook:
    - if port is a lwt tunnel port, use tunnel info attached to
      vlan to set dst_metadata on the skb

CC: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
CC'ing Nikolay for some more eyes as he has been trying to keep the
bridge driver fast path lite.

 net/bridge/br_input.c   |    4 ++++
 net/bridge/br_private.h |    4 ++++
 net/bridge/br_vlan.c    |   55 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 83f356f..96602a1 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -262,6 +262,10 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
 		return RX_HANDLER_CONSUMED;
 
 	p = br_port_get_rcu(skb->dev);
+	if (p->flags & BR_LWT_VLAN) {
+		if (br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p)))
+			goto drop;
+	}
 
 	if (unlikely(is_link_local_ether_addr(dest))) {
 		u16 fwd_mask = p->br->group_fwd_mask_required;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f68e360..68a23c5 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -804,6 +804,10 @@ int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
 int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id);
 bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
 			    struct net_bridge_vlan *v);
+int br_handle_ingress_vlan_tunnel(struct sk_buff *skb, struct net_bridge_port *p,
+				  struct net_bridge_vlan_group *vg);
+int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
+				 struct net_bridge_vlan *vlan);
 
 static inline struct net_bridge_vlan_group *br_vlan_group(
 					const struct net_bridge *br)
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 2040f08..6cf2344 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -405,6 +405,11 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
 
 	if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
 		skb->vlan_tci = 0;
+
+	if (br_handle_egress_vlan_tunnel(skb, v)) {
+		kfree_skb(skb);
+		return NULL;
+	}
 out:
 	return skb;
 }
@@ -1213,3 +1218,53 @@ int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid)
 
 	return 0;
 }
+
+int br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
+				  struct net_bridge_port *p,
+				  struct net_bridge_vlan_group *vg)
+{
+	struct ip_tunnel_info *tinfo = skb_tunnel_info(skb);
+	struct net_bridge_vlan *vlan;
+
+	if (!vg || !tinfo)
+		return 0;
+
+	/* if already tagged, ignore */
+	if (skb_vlan_tagged(skb))
+		return 0;
+
+	/* lookup vid, given tunnel id */
+	vlan = br_vlan_tunnel_lookup(&vg->tunnel_hash, tinfo->key.tun_id);
+	if (!vlan)
+		return 0;
+
+	skb_dst_drop(skb);
+
+	__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
+
+	return 0;
+}
+
+int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
+				 struct net_bridge_vlan *vlan)
+{
+	__be32 tun_id;
+	int err;
+
+	if (!vlan || !vlan->tinfo.tunnel_id)
+		return 0;
+
+	if (unlikely(!skb_vlan_tag_present(skb)))
+		return 0;
+
+	skb_dst_drop(skb);
+	tun_id = tunnel_id_to_key32(vlan->tinfo.tunnel_id);
+
+	err = skb_vlan_pop(skb);
+	if (err)
+		return err;
+
+	skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst));
+
+	return 0;
+}
-- 
1.7.10.4

^ permalink raw reply related

* [RFC PATCH net-next 4/5] bridge: vlan lwt and dst_metadata netlink support
From: Roopa Prabhu @ 2017-01-21  5:46 UTC (permalink / raw)
  To: netdev; +Cc: davem, stephen, nikolay, tgraf, hannes, jbenc, pshelar, dsa, hadi
In-Reply-To: <1484977616-1541-1-git-send-email-roopa@cumulusnetworks.com>

From: Roopa Prabhu <roopa@cumulusnetworks.com>

This patch adds support to attach per vlan tunnel info dst
metadata. This enables bridge driver to map vlan to tunnel_info
at ingress and egress

The initial use case is vlan to vni bridging, but the api is generic
to extend to any tunnel_info in the future:
    - Uapi to configure/unconfigure/dump per vlan tunnel data
    - netlink functions to configure vlan and tunnel_info mapping
    - Introduces bridge port flag BR_LWT_VLAN to enable attach/detach
    dst_metadata to bridged packets on ports.

Use case:
example use for this is a vxlan bridging gateway or vtep
which maps vlans to vn-segments (or vnis). User can configure
per-vlan tunnel information which the bridge driver can use
to bridge vlan into the corresponding tunnel.

CC: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
CC'ing Nikolay for some more eyes as he has been trying to keep the
bridge driver fast path lite.

 include/linux/if_bridge.h |    1 +
 net/bridge/br_input.c     |    1 +
 net/bridge/br_netlink.c   |  410 ++++++++++++++++++++++++++++++++++++++-------
 net/bridge/br_private.h   |   18 ++
 net/bridge/br_vlan.c      |  138 ++++++++++++++-
 5 files changed, 507 insertions(+), 61 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..36ff611 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC	BIT(9)
 #define BR_PROXYARP_WIFI	BIT(10)
 #define BR_MCAST_FLOOD		BIT(11)
+#define BR_LWT_VLAN		BIT(12)
 
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 855b72f..83f356f 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -20,6 +20,7 @@
 #include <net/arp.h>
 #include <linux/export.h>
 #include <linux/rculist.h>
+#include <net/dst_metadata.h>
 #include "br_private.h"
 
 /* Hook for brouter */
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 71c7453..df997ad 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -17,17 +17,30 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <uapi/linux/if_bridge.h>
+#include <net/dst_metadata.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
 
-static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
-				u32 filter_mask)
+static size_t br_get_vlan_tinfo_size(void)
 {
+	return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
+		  nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
+		  nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
+		  nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
+}
+
+static int __get_num_vlan_infos(struct net_bridge_port *p,
+				struct net_bridge_vlan_group *vg,
+				u32 filter_mask, int *num_vtinfos)
+{
+	struct net_bridge_vlan *vbegin = NULL, *vend = NULL;
+	struct net_bridge_vlan *vtbegin = NULL, *vtend = NULL;
 	struct net_bridge_vlan *v;
-	u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
+	bool get_tinfos = (p && p->flags & BR_LWT_VLAN) ? true: false;
+	bool vcontinue, vtcontinue;
+	int num_vinfos = 0;
 	u16 flags, pvid;
-	int num_vlans = 0;
 
 	if (!(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
 		return 0;
@@ -36,6 +49,8 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
 	/* Count number of vlan infos */
 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
 		flags = 0;
+		vcontinue = false;
+		vtcontinue = false;
 		/* only a context, bridge vlan not activated */
 		if (!br_vlan_should_use(v))
 			continue;
@@ -45,47 +60,79 @@ static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
 		if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
 			flags |= BRIDGE_VLAN_INFO_UNTAGGED;
 
-		if (vid_range_start == 0) {
-			goto initvars;
-		} else if ((v->vid - vid_range_end) == 1 &&
-			flags == vid_range_flags) {
-			vid_range_end = v->vid;
+		if (!vbegin) {
+			vbegin = v;
+			vend = v;
+			vcontinue = true;
+		} else if ((v->vid - vend->vid) == 1 &&
+			flags == vbegin->flags) {
+			vend = v;
+			vcontinue = true;
+		}
+
+		if (!vcontinue) {
+			if ((vend->vid - vbegin->vid) > 0)
+				num_vinfos += 2;
+			else
+				num_vinfos += 1;
+		}
+
+		if (!get_tinfos && !v->tinfo.tunnel_id)
 			continue;
-		} else {
-			if ((vid_range_end - vid_range_start) > 0)
-				num_vlans += 2;
+
+		if (!vtbegin) {
+			vtbegin = v;
+			vtend = v;
+			vtcontinue = true;
+		} else if ((v->vid - vtend->vid) == 1 &&
+		    vlan_tunnel_id_isrange(vtend, v)) {
+			vtend = v;
+			vtcontinue = true;
+		}
+
+		if (!vtcontinue) {
+			if ((vtend->vid - vtbegin->vid) > 0)
+				num_vtinfos += 2;
 			else
-				num_vlans += 1;
+				num_vtinfos += 1;
+			vbegin = NULL;
+			vend = NULL;
 		}
-initvars:
-		vid_range_start = v->vid;
-		vid_range_end = v->vid;
-		vid_range_flags = flags;
 	}
 
-	if (vid_range_start != 0) {
-		if ((vid_range_end - vid_range_start) > 0)
-			num_vlans += 2;
+	if (vbegin) {
+		if ((vend->vid - vbegin->vid) > 0)
+			num_vinfos += 2;
 		else
-			num_vlans += 1;
+			num_vinfos += 1;
 	}
 
-	return num_vlans;
+	if (get_tinfos && vtbegin && vtbegin->tinfo.tunnel_id) {
+		if ((vtend->vid - vtbegin->vid) > 0)
+			*num_vtinfos += 2;
+		else
+			*num_vtinfos += 1;
+	}
+
+	return num_vinfos;
 }
 
-static int br_get_num_vlan_infos(struct net_bridge_vlan_group *vg,
-				 u32 filter_mask)
+static int br_get_num_vlan_infos(struct net_bridge_port *p,
+				 struct net_bridge_vlan_group *vg,
+				 int *num_tinfos, u32 filter_mask)
 {
 	int num_vlans;
 
 	if (!vg)
 		return 0;
 
-	if (filter_mask & RTEXT_FILTER_BRVLAN)
+	if (filter_mask & RTEXT_FILTER_BRVLAN) {
+		*num_tinfos = vg->num_vlans;
 		return vg->num_vlans;
+	}
 
 	rcu_read_lock();
-	num_vlans = __get_num_vlan_infos(vg, filter_mask);
+	num_vlans = __get_num_vlan_infos(p, vg, filter_mask, num_tinfos);
 	rcu_read_unlock();
 
 	return num_vlans;
@@ -95,9 +142,10 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
 					   u32 filter_mask)
 {
 	struct net_bridge_vlan_group *vg = NULL;
-	struct net_bridge_port *p;
+	struct net_bridge_port *p = NULL;
 	struct net_bridge *br;
-	int num_vlan_infos;
+	int num_vlan_infos, num_vlan_tinfos = 0;
+	size_t retsize = 0;
 
 	rcu_read_lock();
 	if (br_port_exists(dev)) {
@@ -107,11 +155,15 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
 		br = netdev_priv(dev);
 		vg = br_vlan_group_rcu(br);
 	}
-	num_vlan_infos = br_get_num_vlan_infos(vg, filter_mask);
+	num_vlan_infos = br_get_num_vlan_infos(p, vg, &num_vlan_tinfos,
+					       filter_mask);
 	rcu_read_unlock();
 
 	/* Each VLAN is returned in bridge_vlan_info along with flags */
-	return num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
+	retsize =  num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info)) +
+			num_vlan_tinfos * br_get_vlan_tinfo_size();
+
+	return retsize;
 }
 
 static inline size_t br_port_info_size(void)
@@ -191,7 +243,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	    nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
 	    nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
 		       p->topology_change_ack) ||
-	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending))
+	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
+	    nla_put_u8(skb, IFLA_BRPORT_LWT_VLAN, !!(p->flags & BR_LWT_VLAN)))
 		return -EMSGSIZE;
 
 	timerval = br_timer_value(&p->message_age_timer);
@@ -216,6 +269,34 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	return 0;
 }
 
+static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
+                              __be64 tunnel_id, u16 flags)
+{
+    __be32 tid = tunnel_id_to_key32(tunnel_id);
+    struct nlattr *tmap;
+
+	tmap = nla_nest_start(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
+	if (!tmap)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
+            be32_to_cpu(tid)))
+		goto nla_put_failure;
+	if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
+			vid))
+		goto nla_put_failure;
+	if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
+			flags))
+		goto nla_put_failure;
+	nla_nest_end(skb, tmap);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, tmap);
+
+	return -EMSGSIZE;
+}
+
 static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
 				    u16 vid_end, u16 flags)
 {
@@ -249,20 +330,24 @@ static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
 }
 
 static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
+					 struct net_bridge_port *p,
 					 struct net_bridge_vlan_group *vg)
 {
+	struct net_bridge_vlan *vbegin = NULL, *vend = NULL;
+	struct net_bridge_vlan *vtbegin = NULL, *vtend = NULL;
+	bool fill_tinfos = (p && p->flags & BR_LWT_VLAN) ? true: false;
 	struct net_bridge_vlan *v;
-	u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
+	bool vcontinue, vtcontinue;
 	u16 flags, pvid;
-	int err = 0;
+	int err;
 
-	/* Pack IFLA_BRIDGE_VLAN_INFO's for every vlan
-	 * and mark vlan info with begin and end flags
-	 * if vlaninfo represents a range
-	 */
 	pvid = br_get_pvid(vg);
+	/* Count number of vlan infos */
 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
 		flags = 0;
+		vcontinue = false;
+		vtcontinue = false;
+		/* only a context, bridge vlan not activated */
 		if (!br_vlan_should_use(v))
 			continue;
 		if (v->vid == pvid)
@@ -271,44 +356,103 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
 		if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
 			flags |= BRIDGE_VLAN_INFO_UNTAGGED;
 
-		if (vid_range_start == 0) {
-			goto initvars;
-		} else if ((v->vid - vid_range_end) == 1 &&
-			flags == vid_range_flags) {
-			vid_range_end = v->vid;
-			continue;
-		} else {
-			err = br_fill_ifvlaninfo_range(skb, vid_range_start,
-						       vid_range_end,
-						       vid_range_flags);
+		if (!vbegin) {
+			vbegin = v;
+			vend = v;
+			vcontinue = true;
+		} else if ((v->vid - vend->vid) == 1 &&
+			flags == vbegin->flags) {
+			vend = v;
+			vcontinue = true;
+		}
+
+		if (!vcontinue) {
+			err = br_fill_ifvlaninfo_range(skb,
+						       vbegin->vid,
+						       vend->vid,
+						       vbegin->flags);
 			if (err)
 				return err;
+			vbegin = vend = NULL;
+		}
+
+		if (!fill_tinfos || !v->tinfo.tunnel_id)
+			continue;
+
+		if (!vtbegin) {
+			vtbegin = v;
+			vtend = v;
+			vtcontinue = true;
+		} else if ((v->vid - vtend->vid) == 1 &&
+		    vlan_tunnel_id_isrange(vtend, v)) {
+			vtend = v;
+			vtcontinue = true;
 		}
 
-initvars:
-		vid_range_start = v->vid;
-		vid_range_end = v->vid;
-		vid_range_flags = flags;
+		if (!vtcontinue && vtbegin->tinfo.tunnel_id) {
+			if ((vtend->vid - vtbegin->vid) > 0) {
+				err = br_fill_vlan_tinfo(skb, vbegin->vid,
+							 vbegin->tinfo.tunnel_id,
+						BRIDGE_VLAN_INFO_RANGE_BEGIN);
+				if (err)
+					return err;
+				err = br_fill_vlan_tinfo(skb, vend->vid,
+							 vend->tinfo.tunnel_id,
+						BRIDGE_VLAN_INFO_RANGE_END);
+				if (err)
+					return err;
+			} else {
+				err = br_fill_vlan_tinfo(skb, vbegin->vid,
+							 vbegin->tinfo.tunnel_id,
+							 0);
+				if (err)
+					return err;
+			}
+			vbegin = NULL;
+			vend = NULL;
+		}
 	}
 
-	if (vid_range_start != 0) {
-		/* Call it once more to send any left over vlans */
-		err = br_fill_ifvlaninfo_range(skb, vid_range_start,
-					       vid_range_end,
-					       vid_range_flags);
+	if (vbegin) {
+		err = br_fill_ifvlaninfo_range(skb, vbegin->vid,
+					       vend->vid,
+					       vbegin->flags);
 		if (err)
 			return err;
 	}
 
+	if (fill_tinfos && vtbegin && vtbegin->tinfo.tunnel_id) {
+		if ((vtend->vid - vtbegin->vid) > 0) {
+			err = br_fill_vlan_tinfo(skb, vbegin->vid,
+						 vbegin->tinfo.tunnel_id,
+						 BRIDGE_VLAN_INFO_RANGE_BEGIN);
+			if (err)
+				return err;
+			err = br_fill_vlan_tinfo(skb, vend->vid,
+						 vend->tinfo.tunnel_id,
+						 BRIDGE_VLAN_INFO_RANGE_END);
+			if (err)
+				return err;
+		} else {
+			err = br_fill_vlan_tinfo(skb, vbegin->vid,
+						 vbegin->tinfo.tunnel_id, 0);
+			if (err)
+				return err;
+		}
+	}
+
 	return 0;
 }
 
 static int br_fill_ifvlaninfo(struct sk_buff *skb,
+			      struct net_bridge_port *p,
 			      struct net_bridge_vlan_group *vg)
 {
 	struct bridge_vlan_info vinfo;
 	struct net_bridge_vlan *v;
+	bool fill_tinfos = (p && p->flags & BR_LWT_VLAN) ? true : false;
 	u16 pvid;
+	int err;
 
 	pvid = br_get_pvid(vg);
 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
@@ -326,6 +470,14 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
 		if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
 			    sizeof(vinfo), &vinfo))
 			goto nla_put_failure;
+
+		if (!fill_tinfos || !v->tinfo.tunnel_id)
+			continue;
+
+		err = br_fill_vlan_tinfo(skb, v->vid,
+					 v->tinfo.tunnel_id, 0);
+		if (err)
+			return err;
 	}
 
 	return 0;
@@ -411,9 +563,9 @@ static int br_fill_ifinfo(struct sk_buff *skb,
 			goto nla_put_failure;
 		}
 		if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
-			err = br_fill_ifvlaninfo_compressed(skb, vg);
+			err = br_fill_ifvlaninfo_compressed(skb, port, vg);
 		else
-			err = br_fill_ifvlaninfo(skb, vg);
+			err = br_fill_ifvlaninfo(skb, port, vg);
 		rcu_read_unlock();
 		if (err)
 			goto nla_put_failure;
@@ -514,6 +666,127 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
 	return err;
 }
 
+static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
+	[IFLA_BRIDGE_VLAN_TUNNEL_ID]= { .type = NLA_U32 },
+	[IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
+	[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
+};
+
+static int br_add_vlan_tunnel_info(struct net_bridge *br,
+				   struct net_bridge_port *p, int cmd,
+				   u16 vid, u32 tun_id)
+{
+	int err;
+
+	switch (cmd) {
+	case RTM_SETLINK:
+		if (p) {
+			/* if the MASTER flag is set this will act on the global
+			 * per-VLAN entry as well
+			 */
+			err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
+			if (err)
+				break;
+		} else {
+			return -EINVAL;
+		}
+
+		break;
+
+	case RTM_DELLINK:
+		if (p)
+			nbp_vlan_tunnel_info_delete(p, vid);
+		else
+			return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+struct vtunnel_info {
+	u32	tunid;
+	u16	vid;
+	u16	flags;
+};
+
+static int br_parse_vlan_tunnel_info(struct nlattr *attr,
+				     struct vtunnel_info *tinfo)
+{
+	struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
+	u32 tun_id;
+	u16 vid, flags;
+	int err;
+
+	err = nla_parse_nested(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
+			       attr, vlan_tunnel_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[IFLA_BRIDGE_VLAN_TUNNEL_ID])
+		tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
+	else
+		return -EINVAL;
+
+	if (tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]) {
+		vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
+		if (vid >= VLAN_VID_MASK)
+			return -ERANGE;
+	} else {
+		return -EINVAL;
+	}
+
+	if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
+		flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
+
+	tinfo->tunid = tun_id;
+	tinfo->vid = vid;
+	tinfo->flags = flags;
+
+	return 0;
+}
+
+static int br_process_vlan_tunnel_info(struct net_bridge *br,
+				       struct net_bridge_port *p, int cmd,
+				       struct vtunnel_info *tinfo_curr,
+				       struct vtunnel_info *tinfo_last)
+{
+	int t, v;
+	int err;
+
+	if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+		if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
+			return -EINVAL;
+		memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
+	} else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
+		if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
+			return -EINVAL;
+		if ((tinfo_curr->vid - tinfo_last->vid) !=
+		    (tinfo_curr->tunid - tinfo_last->tunid))
+			return -EINVAL;
+		/* XXX: tun id and vlan id attrs must be same
+		 */
+		t = tinfo_last->tunid;
+		for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
+			err = br_add_vlan_tunnel_info(br, p, cmd,
+							  v, t);
+			if (err)
+				return err;
+			t++;
+		}
+		memset(tinfo_last, 0, sizeof(struct vtunnel_info));
+		memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
+	} else {
+		err = br_add_vlan_tunnel_info(br, p, cmd,
+					      tinfo_curr->vid,
+					      tinfo_curr->tunid);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int br_afspec(struct net_bridge *br,
 		     struct net_bridge_port *p,
 		     struct nlattr *af_spec,
@@ -522,10 +795,30 @@ static int br_afspec(struct net_bridge *br,
 	struct bridge_vlan_info *vinfo_start = NULL;
 	struct bridge_vlan_info *vinfo = NULL;
 	struct nlattr *attr;
+	struct vtunnel_info tinfo_last = {
+		.tunid = 0,
+		.vid = 0,
+		.flags = 0};
+	struct vtunnel_info tinfo_curr = {
+		.tunid = 0,
+		.vid = 0,
+		.flags = 0};
 	int err = 0;
 	int rem;
 
 	nla_for_each_nested(attr, af_spec, rem) {
+		if (nla_type(attr) == IFLA_BRIDGE_VLAN_TUNNEL_INFO) {
+			err = br_parse_vlan_tunnel_info(attr, &tinfo_curr);
+			if (err)
+				return err;
+			err = br_process_vlan_tunnel_info(br, p, cmd,
+							  &tinfo_curr,
+							  &tinfo_last);
+			if (err)
+				return err;
+			continue;
+		}
+
 		if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
 			continue;
 		if (nla_len(attr) != sizeof(struct bridge_vlan_info))
@@ -638,6 +931,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
 	br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
 	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
 	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
+	br_set_port_flag(p, tb, IFLA_BRPORT_LWT_VLAN, BR_LWT_VLAN);
 
 	if (tb[IFLA_BRPORT_COST]) {
 		err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8ce621e..f68e360 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -91,6 +91,11 @@ struct br_vlan_stats {
 	struct u64_stats_sync syncp;
 };
 
+struct br_tunnel_info {
+	__be64			tunnel_id;
+	struct metadata_dst	*tunnel_dst;
+};
+
 /**
  * struct net_bridge_vlan - per-vlan entry
  *
@@ -113,6 +118,7 @@ struct br_vlan_stats {
  */
 struct net_bridge_vlan {
 	struct rhash_head		vnode;
+	struct rhash_head		tnode;
 	u16				vid;
 	u16				flags;
 	struct br_vlan_stats __percpu	*stats;
@@ -124,6 +130,9 @@ struct net_bridge_vlan {
 		atomic_t		refcnt;
 		struct net_bridge_vlan	*brvlan;
 	};
+
+	struct br_tunnel_info		tinfo;
+
 	struct list_head		vlist;
 
 	struct rcu_head			rcu;
@@ -145,6 +154,7 @@ struct net_bridge_vlan {
  */
 struct net_bridge_vlan_group {
 	struct rhashtable		vlan_hash;
+	struct rhashtable		tunnel_hash;
 	struct list_head		vlan_list;
 	u16				num_vlans;
 	u16				pvid;
@@ -786,6 +796,14 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
 int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask);
 void br_vlan_get_stats(const struct net_bridge_vlan *v,
 		       struct br_vlan_stats *stats);
+int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
+			   struct net_bridge_vlan *vlan, u32 tun_id);
+int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
+                           struct net_bridge_vlan *vlan);
+int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid);
+int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id);
+bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
+			    struct net_bridge_vlan *v);
 
 static inline struct net_bridge_vlan_group *br_vlan_group(
 					const struct net_bridge *br)
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index b6de4f4..2040f08 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -3,6 +3,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <net/switchdev.h>
+#include <net/dst_metadata.h>
 
 #include "br_private.h"
 
@@ -31,6 +32,31 @@ static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid)
 	return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params);
 }
 
+static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
+				    const void *ptr)
+{
+	const struct net_bridge_vlan *vle = ptr;
+	__be64 tunid = *(__be64 *)arg->key;
+
+	return vle->tinfo.tunnel_id != tunid;
+}
+
+static const struct rhashtable_params br_vlan_tunnel_rht_params = {
+	.head_offset = offsetof(struct net_bridge_vlan, tnode),
+	.key_offset = offsetof(struct net_bridge_vlan, tinfo.tunnel_id),
+	.key_len = sizeof(__be64),
+	.nelem_hint = 3,
+	.locks_mul = 1,
+	.obj_cmpfn = br_vlan_tunid_cmp,
+	.automatic_shrinking = true,
+};
+
+static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl,
+						     u64 tunnel_id)
+{
+	return rhashtable_lookup_fast(tbl, &tunnel_id, br_vlan_tunnel_rht_params);
+}
+
 static void __vlan_add_pvid(struct net_bridge_vlan_group *vg, u16 vid)
 {
 	if (vg->pvid == vid)
@@ -325,6 +351,7 @@ static void __vlan_group_free(struct net_bridge_vlan_group *vg)
 {
 	WARN_ON(!list_empty(&vg->vlan_list));
 	rhashtable_destroy(&vg->vlan_hash);
+	rhashtable_destroy(&vg->tunnel_hash);
 	kfree(vg);
 }
 
@@ -613,6 +640,8 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
 	br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid);
 	br_fdb_delete_by_port(br, NULL, vid, 0);
 
+	__vlan_tunnel_info_del(vg, v);
+
 	return __vlan_del(v);
 }
 
@@ -918,6 +947,9 @@ int br_vlan_init(struct net_bridge *br)
 	ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
 	if (ret)
 		goto err_rhtbl;
+	ret = rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
+	if (ret)
+		goto err_rhtbl2;
 	INIT_LIST_HEAD(&vg->vlan_list);
 	br->vlan_proto = htons(ETH_P_8021Q);
 	br->default_pvid = 1;
@@ -932,6 +964,8 @@ int br_vlan_init(struct net_bridge *br)
 	return ret;
 
 err_vlan_add:
+	rhashtable_destroy(&vg->tunnel_hash);
+err_rhtbl2:
 	rhashtable_destroy(&vg->vlan_hash);
 err_rhtbl:
 	kfree(vg);
@@ -960,7 +994,10 @@ int nbp_vlan_init(struct net_bridge_port *p)
 
 	ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
 	if (ret)
-		goto err_rhtbl;
+		goto err_rhtbl1;
+	ret = rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
+	if (ret)
+		goto err_rhtbl2;
 	INIT_LIST_HEAD(&vg->vlan_list);
 	rcu_assign_pointer(p->vlgrp, vg);
 	if (p->br->default_pvid) {
@@ -976,9 +1013,11 @@ int nbp_vlan_init(struct net_bridge_port *p)
 err_vlan_add:
 	RCU_INIT_POINTER(p->vlgrp, NULL);
 	synchronize_rcu();
-	rhashtable_destroy(&vg->vlan_hash);
+	rhashtable_destroy(&vg->tunnel_hash);
 err_vlan_enabled:
-err_rhtbl:
+err_rhtbl2:
+	rhashtable_destroy(&vg->vlan_hash);
+err_rhtbl1:
 	kfree(vg);
 
 	goto out;
@@ -1081,3 +1120,96 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
 		stats->tx_packets += txpackets;
 	}
 }
+
+bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v_end,
+			    struct net_bridge_vlan *v)
+{
+	/* XXX: check other tunnel attributes */
+	return (be32_to_cpu(tunnel_id_to_key32(v_end->tinfo.tunnel_id)) -
+		be32_to_cpu(tunnel_id_to_key32(v->tinfo.tunnel_id)) == 1);
+}
+
+int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
+			   struct net_bridge_vlan *vlan, u32 tun_id)
+{
+	struct metadata_dst *metadata = NULL;
+	__be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id));
+	int err;
+
+	if (vlan->tinfo.tunnel_dst)
+		return -EEXIST;
+
+	metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY,
+				    key, 0);
+	if (!metadata)
+		return -EINVAL;
+
+	metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE;
+	vlan->tinfo.tunnel_dst = metadata;
+	vlan->tinfo.tunnel_id = key;
+
+	err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode,
+					    br_vlan_tunnel_rht_params);
+	if (err)
+		goto out;
+
+	return 0;
+out:
+	dst_release(&vlan->tinfo.tunnel_dst->dst);
+
+	return err;
+}
+
+int __vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
+			   struct net_bridge_vlan *vlan)
+{
+	if (vlan->tinfo.tunnel_dst) {
+		vlan->tinfo.tunnel_id = 0;
+		dst_release(&vlan->tinfo.tunnel_dst->dst);
+
+		rhashtable_remove_fast(&vg->tunnel_hash, &vlan->vnode,
+				       br_vlan_tunnel_rht_params);
+	}
+
+	return 0;
+}
+
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
+int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id)
+{
+	struct net_bridge_vlan_group *vg;
+	struct net_bridge_vlan *vlan;
+
+	ASSERT_RTNL();
+
+	vg = nbp_vlan_group(port);
+	vlan = br_vlan_find(vg, vid);
+	if (!vlan)
+		return -EINVAL;
+
+	__vlan_tunnel_info_add(vg, vlan, tun_id);
+
+	return 0;
+}
+
+/* Must be protected by RTNL.
+ * Must be called with vid in range from 1 to 4094 inclusive.
+ */
+int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid)
+{
+	struct net_bridge_vlan_group *vg;
+	struct net_bridge_vlan *v;
+
+	ASSERT_RTNL();
+
+	vg = nbp_vlan_group(port);
+	v = br_vlan_find(vg, vid);
+	if (!v)
+		return -ENOENT;
+
+	__vlan_tunnel_info_del(vg, v);
+
+	return 0;
+}
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH] net: xilinx: constify net_device_ops structures
From: Bhumika Goyal @ 2017-01-21  6:08 UTC (permalink / raw)
  To: julia.lawall, michal.simek, soren.brinkmann, netdev,
	linux-arm-kernel, linux-kernel
  Cc: Bhumika Goyal

Declare net_device_ops structures as const as they are only stored in
the netdev_ops field of a net_device structure. This field is of type
const, so net_device_ops structures having same properties can be made
const too.
Done using Coccinelle:

@r1 disable optional_qualifier@
identifier i;
position p;
@@
static struct net_device_ops i@p={...};

@ok1@
identifier r1.i;
position p;
struct net_device ndev;
@@
ndev.netdev_ops=&i@p

@bad@
position p!={r1.p,ok1.p};
identifier r1.i;
@@
i@p

@depends on !bad disable optional_qualifier@
identifier r1.i;
@@
+const
struct net_device_ops i;

File size before:
   text	   data	    bss	    dec	    hex	filename
   6201	    744	      0	   6945	   1b21 ethernet/xilinx/xilinx_emaclite.o

File size after:
   text	   data	    bss	    dec	    hex	filename
   6745	    192	      0	   6937	   1b19 ethernet/xilinx/xilinx_emaclite.o

Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
 drivers/net/ethernet/xilinx/xilinx_emaclite.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 93dc10b..546f569 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -1065,7 +1065,7 @@ static bool get_bool(struct platform_device *ofdev, const char *s)
 	}
 }
 
-static struct net_device_ops xemaclite_netdev_ops;
+static const struct net_device_ops xemaclite_netdev_ops;
 
 /**
  * xemaclite_of_probe - Probe method for the Emaclite device.
@@ -1219,7 +1219,7 @@ static int xemaclite_of_remove(struct platform_device *of_dev)
 }
 #endif
 
-static struct net_device_ops xemaclite_netdev_ops = {
+static const struct net_device_ops xemaclite_netdev_ops = {
 	.ndo_open		= xemaclite_open,
 	.ndo_stop		= xemaclite_close,
 	.ndo_start_xmit		= xemaclite_send,
-- 
1.9.1

^ permalink raw reply related

* [PATCH] net: moxa: constify net_device_ops structures
From: Bhumika Goyal @ 2017-01-21  6:14 UTC (permalink / raw)
  To: julia.lawall, dan.carpenter, davem, netdev, linux-kernel; +Cc: Bhumika Goyal

Declare net_device_ops structures as const as they are only stored in
the netdev_ops field of a net_device structure. This field is of type
const, so net_device_ops structures having same properties can be made
const too.
Done using Coccinelle:

@r1 disable optional_qualifier@
identifier i;
position p;
@@
static struct net_device_ops i@p={...};

@ok1@
identifier r1.i;
position p;
struct net_device ndev;
@@
ndev.netdev_ops=&i@p

@bad@
position p!={r1.p,ok1.p};
identifier r1.i;
@@
i@p

@depends on !bad disable optional_qualifier@
identifier r1.i;
@@
+const
struct net_device_ops i;

File size before:
   text	   data	    bss	    dec	    hex	filename
   4821	    744	      0	   5565	   15bd ethernet/moxa/moxart_ether.o

File size after:
   text	   data	    bss	    dec	    hex	filename
   5373	    192	      0	   5565	   15bd ethernet/moxa/moxart_ether.o

Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
 drivers/net/ethernet/moxa/moxart_ether.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index 9774b50..6a6525f 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -436,7 +436,7 @@ static void moxart_mac_set_rx_mode(struct net_device *ndev)
 	spin_unlock_irq(&priv->txlock);
 }
 
-static struct net_device_ops moxart_netdev_ops = {
+static const struct net_device_ops moxart_netdev_ops = {
 	.ndo_open		= moxart_mac_open,
 	.ndo_stop		= moxart_mac_stop,
 	.ndo_start_xmit		= moxart_mac_start_xmit,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2] net: moxa: constify net_device_ops structures
From: Bhumika Goyal @ 2017-01-21  6:57 UTC (permalink / raw)
  To: julia.lawall, dan.carpenter, davem, netdev, linux-kernel; +Cc: Bhumika Goyal

Declare net_device_ops structure as const as it is only stored in
the netdev_ops field of a net_device structure. This field is of type
const, so net_device_ops structures having same properties can be made
const too.
Done using Coccinelle:

@r1 disable optional_qualifier@
identifier i;
position p;
@@
static struct net_device_ops i@p={...};

@ok1@
identifier r1.i;
position p;
struct net_device ndev;
@@
ndev.netdev_ops=&i@p

@bad@
position p!={r1.p,ok1.p};
identifier r1.i;
@@
i@p

@depends on !bad disable optional_qualifier@
identifier r1.i;
@@
+const
struct net_device_ops i;

File size before:
   text	   data	    bss	    dec	    hex	filename
   4821	    744	      0	   5565	   15bd ethernet/moxa/moxart_ether.o

File size after:
   text	   data	    bss	    dec	    hex	filename
   5373	    192	      0	   5565	   15bd ethernet/moxa/moxart_ether.o

Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
Changes in v2:
* Corrected the commit message.

 drivers/net/ethernet/moxa/moxart_ether.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index 9774b50..6a6525f 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -436,7 +436,7 @@ static void moxart_mac_set_rx_mode(struct net_device *ndev)
 	spin_unlock_irq(&priv->txlock);
 }
 
-static struct net_device_ops moxart_netdev_ops = {
+static const struct net_device_ops moxart_netdev_ops = {
 	.ndo_open		= moxart_mac_open,
 	.ndo_stop		= moxart_mac_stop,
 	.ndo_start_xmit		= moxart_mac_start_xmit,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2] net: xilinx: constify net_device_ops structure
From: Bhumika Goyal @ 2017-01-21  6:58 UTC (permalink / raw)
  To: julia.lawall, michal.simek, soren.brinkmann, netdev,
	linux-arm-kernel, linux-kernel
  Cc: Bhumika Goyal

Declare net_device_ops structure as const as it is only stored in
the netdev_ops field of a net_device structure. This field is of type
const, so net_device_ops structures having same properties can be made
const too.
Done using Coccinelle:

@r1 disable optional_qualifier@
identifier i;
position p;
@@
static struct net_device_ops i@p={...};

@ok1@
identifier r1.i;
position p;
struct net_device ndev;
@@
ndev.netdev_ops=&i@p

@bad@
position p!={r1.p,ok1.p};
identifier r1.i;
@@
i@p

@depends on !bad disable optional_qualifier@
identifier r1.i;
@@
+const
struct net_device_ops i;

File size before:
   text	   data	    bss	    dec	    hex	filename
   6201	    744	      0	   6945	   1b21 ethernet/xilinx/xilinx_emaclite.o

File size after:
   text	   data	    bss	    dec	    hex	filename
   6745	    192	      0	   6937	   1b19 ethernet/xilinx/xilinx_emaclite.o

Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
Changes in v2:
* Corrected the commit message.

 drivers/net/ethernet/xilinx/xilinx_emaclite.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 93dc10b..546f569 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -1065,7 +1065,7 @@ static bool get_bool(struct platform_device *ofdev, const char *s)
 	}
 }
 
-static struct net_device_ops xemaclite_netdev_ops;
+static const struct net_device_ops xemaclite_netdev_ops;
 
 /**
  * xemaclite_of_probe - Probe method for the Emaclite device.
@@ -1219,7 +1219,7 @@ static int xemaclite_of_remove(struct platform_device *of_dev)
 }
 #endif
 
-static struct net_device_ops xemaclite_netdev_ops = {
+static const struct net_device_ops xemaclite_netdev_ops = {
 	.ndo_open		= xemaclite_open,
 	.ndo_stop		= xemaclite_close,
 	.ndo_start_xmit		= xemaclite_send,
-- 
1.9.1

^ permalink raw reply related

* [PATCH cumulus-4.1.y 4/5] vxlan: don't flush static fdb entries on admin down
From: Roopa Prabhu @ 2017-01-21  7:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

From: Roopa Prabhu <roopa@cumulusnetworks.com>

This patch skips flushing static fdb entries in
ndo_stop, but flushes all fdb entries during vxlan
device delete. This is consistent with the bridge
driver fdb

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 7300586..3314090 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2365,7 +2365,7 @@ static int vxlan_open(struct net_device *dev)
 }
 
 /* Purge the forwarding table */
-static void vxlan_flush(struct vxlan_dev *vxlan)
+static void vxlan_flush(struct vxlan_dev *vxlan, int do_all)
 {
 	unsigned int h;
 
@@ -2375,6 +2375,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 		hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
 			struct vxlan_fdb *f
 				= container_of(p, struct vxlan_fdb, hlist);
+			if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP)))
+				continue;
 			/* the all_zeros_mac entry is deleted at vxlan_uninit */
 			if (!is_zero_ether_addr(f->eth_addr))
 				vxlan_fdb_destroy(vxlan, f);
@@ -2396,7 +2398,7 @@ static int vxlan_stop(struct net_device *dev)
 
 	del_timer_sync(&vxlan->age_timer);
 
-	vxlan_flush(vxlan);
+	vxlan_flush(vxlan, 0);
 	vxlan_sock_release(vxlan);
 
 	return ret;
@@ -3069,6 +3071,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
 
+	vxlan_flush(vxlan, 1);
+
 	spin_lock(&vn->sock_lock);
 	if (!hlist_unhashed(&vxlan->hlist))
 		hlist_del_rcu(&vxlan->hlist);
-- 
1.9.1

^ permalink raw reply related

* [PATCH cumulus-4.1.y 5/5] vxlan: do not age static remote mac entries
From: Roopa Prabhu @ 2017-01-21  7:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

From: Balakrishnan Raman <ramanb@cumulusnetworks.com>

Mac aging is applicable only for dynamically learnt remote mac
entries. Check for user configured static remote mac entries
and skip aging.

Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 3314090..312240c 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2279,7 +2279,7 @@ static void vxlan_cleanup(unsigned long arg)
 				= container_of(p, struct vxlan_fdb, hlist);
 			unsigned long timeout;
 
-			if (f->state & NUD_PERMANENT)
+			if (f->state & (NUD_PERMANENT | NUD_NOARP))
 				continue;
 
 			timeout = f->used + vxlan->cfg.age_interval * HZ;
-- 
1.9.1

^ permalink raw reply related

* [PATCH cumulus-4.1.y 3/5] vxlan: enforce precedence for static over dynamic fdb entry
From: Roopa Prabhu @ 2017-01-21  7:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

From: Wilson Kok <wkok@cumulusnetworks.com>

This patch enforces fdb state correctly when deciding
to add or update an existing fdb. It makes sure static fdb
entries are not replaced by dynamic fdb entries.

Signed-off-by: Wilson Kok <wkok@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 72b99ff..7300586 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -628,6 +628,10 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
 			return -EEXIST;
 		}
 		if (f->state != state) {
+			if ((f->state & NUD_PERMANENT) &&
+			    !(state & NUD_PERMANENT))
+				return -EINVAL;
+
 			f->state = state;
 			f->updated = jiffies;
 			notify = 1;
-- 
1.9.1

^ permalink raw reply related

* [PATCH cumulus-4.1.y 1/5] vxlan: flush fdb entries on oper down
From: Roopa Prabhu @ 2017-01-21  7:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar

From: Balakrishnan Raman <ramanb@cumulusnetworks.com>

Flush fdb entries of a vxlan device when its state
changes to oper down. vxlan_stop handles flush on
admin down.

Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 19b1653..15b1c23 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3276,6 +3276,12 @@ static int vxlan_netdevice_event(struct notifier_block *unused,
 		vxlan_handle_lowerdev_unregister(vn, dev);
 	else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
 		vxlan_push_rx_ports(dev);
+	else if (event == NETDEV_CHANGE) {
+		if (dev->netdev_ops == &vxlan_netdev_ops) {
+			if (netif_running(dev) && !netif_oper_up(dev))
+				vxlan_flush(netdev_priv(dev));
+		}
+	}
 
 	return NOTIFY_DONE;
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH cumulus-4.1.y 2/5] vxlan: don't replace fdb entry if nothing changed
From: Roopa Prabhu @ 2017-01-21  7:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

From: Balakrishnan Raman <ramanb@cumulusnetworks.com>

This will avoid unnecessary notifications to userspace.

Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 15b1c23..72b99ff 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -467,12 +467,19 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
 	if (!rd)
 		return 0;
 
-	dst_cache_reset(&rd->dst_cache);
-	rd->remote_ip = *ip;
-	rd->remote_port = port;
-	rd->remote_vni = vni;
-	rd->remote_ifindex = ifindex;
-	return 1;
+	if (!vxlan_addr_equal(&rd->remote_ip, ip) ||
+	    rd->remote_port != port ||
+	    rd->remote_vni != vni ||
+	    rd->remote_ifindex != ifindex) {
+		dst_cache_reset(&rd->dst_cache);
+		rd->remote_ip = *ip;
+		rd->remote_port = port;
+		rd->remote_vni = vni;
+		rd->remote_ifindex = ifindex;
+		return 1;
+	}
+
+	return 0;
 }
 
 /* Add/update destinations for multicast */
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH cumulus-4.1.y 1/5] vxlan: flush fdb entries on oper down
From: Roopa Prabhu @ 2017-01-21  7:41 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

On 1/20/17, 11:40 PM, Roopa Prabhu wrote:
> From: Balakrishnan Raman <ramanb@cumulusnetworks.com>
>
> Flush fdb entries of a vxlan device when its state
> changes to oper down. vxlan_stop handles flush on
> admin down.
>
> Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> ---
>  

pls ignore this series. Accidently hit send in the wrong folder :(

^ permalink raw reply

* [PATCH net-next 1/2] vxlan: don't flush static fdb entries on admin down
From: Roopa Prabhu @ 2017-01-21  7:43 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984599-16712-1-git-send-email-roopa@cumulusnetworks.com>

From: Roopa Prabhu <roopa@cumulusnetworks.com>

This patch skips flushing static fdb entries in
ndo_stop, but flushes all fdb entries during vxlan
device delete. This is consistent with the bridge
driver fdb

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 19b1653..269e515 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2354,7 +2354,7 @@ static int vxlan_open(struct net_device *dev)
 }
 
 /* Purge the forwarding table */
-static void vxlan_flush(struct vxlan_dev *vxlan)
+static void vxlan_flush(struct vxlan_dev *vxlan, int do_all)
 {
 	unsigned int h;
 
@@ -2364,6 +2364,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 		hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
 			struct vxlan_fdb *f
 				= container_of(p, struct vxlan_fdb, hlist);
+			if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP)))
+				continue;
 			/* the all_zeros_mac entry is deleted at vxlan_uninit */
 			if (!is_zero_ether_addr(f->eth_addr))
 				vxlan_fdb_destroy(vxlan, f);
@@ -2385,7 +2387,7 @@ static int vxlan_stop(struct net_device *dev)
 
 	del_timer_sync(&vxlan->age_timer);
 
-	vxlan_flush(vxlan);
+	vxlan_flush(vxlan, 0);
 	vxlan_sock_release(vxlan);
 
 	return ret;
@@ -3058,6 +3060,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
 
+	vxlan_flush(vxlan, 1);
+
 	spin_lock(&vn->sock_lock);
 	if (!hlist_unhashed(&vxlan->hlist))
 		hlist_del_rcu(&vxlan->hlist);
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next 0/2] vxlan: misc fdb fixes
From: Roopa Prabhu @ 2017-01-21  7:43 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar

From: Roopa Prabhu <roopa@cumulusnetworks.com>

Balakrishnan Raman (1):
  vxlan: do not age static remote mac entries

Roopa Prabhu (1):
  vxlan: don't flush static fdb entries on admin down

 drivers/net/vxlan.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH net-next 2/2] vxlan: do not age static remote mac entries
From: Roopa Prabhu @ 2017-01-21  7:43 UTC (permalink / raw)
  To: davem; +Cc: netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984599-16712-1-git-send-email-roopa@cumulusnetworks.com>

From: Balakrishnan Raman <ramanb@cumulusnetworks.com>

Mac aging is applicable only for dynamically learnt remote mac
entries. Check for user configured static remote mac entries
and skip aging.

Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
---
 drivers/net/vxlan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 269e515..2c5bb0a 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2268,7 +2268,7 @@ static void vxlan_cleanup(unsigned long arg)
 				= container_of(p, struct vxlan_fdb, hlist);
 			unsigned long timeout;
 
-			if (f->state & NUD_PERMANENT)
+			if (f->state & (NUD_PERMANENT | NUD_NOARP))
 				continue;
 
 			timeout = f->used + vxlan->cfg.age_interval * HZ;
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH 4/4] xfrm_user: Add new 32/64-agnostic netlink messages
From: kbuild test robot @ 2017-01-21  8:21 UTC (permalink / raw)
  To: Kevin Cernekee
  Cc: kbuild-all, steffen.klassert, herbert, davem, paul, sds, eparis,
	linux-kernel, netdev, selinux, fw, fan.du, dianders, dtor
In-Reply-To: <20170121000507.34381-5-cernekee@chromium.org>

[-- Attachment #1: Type: text/plain, Size: 9722 bytes --]

Hi Kevin,

[auto build test ERROR on ipsec-next/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Kevin-Cernekee/Make-xfrm-usable-by-32-bit-programs/20170121-150712
base:   https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git master
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

>> net/xfrm/xfrm_user_legacy.c:845:5: error: redefinition of 'xfrm_exp_state_notify_legacy'
    int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from net/xfrm/xfrm_user_legacy.c:30:0:
   net/xfrm/xfrm_user.h:131:19: note: previous definition of 'xfrm_exp_state_notify_legacy' was here
    static inline int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> net/xfrm/xfrm_user_legacy.c:863:5: error: redefinition of 'xfrm_notify_sa_legacy'
    int xfrm_notify_sa_legacy(const struct xfrm_state *x, const struct km_event *c)
        ^~~~~~~~~~~~~~~~~~~~~
   In file included from net/xfrm/xfrm_user_legacy.c:30:0:
   net/xfrm/xfrm_user.h:137:19: note: previous definition of 'xfrm_notify_sa_legacy' was here
    static inline int xfrm_notify_sa_legacy(const struct xfrm_state *x,
                      ^~~~~~~~~~~~~~~~~~~~~
>> net/xfrm/xfrm_user_legacy.c:983:5: error: redefinition of 'xfrm_send_acquire_legacy'
    int xfrm_send_acquire_legacy(struct xfrm_state *x,
        ^~~~~~~~~~~~~~~~~~~~~~~~
   In file included from net/xfrm/xfrm_user_legacy.c:30:0:
   net/xfrm/xfrm_user.h:143:19: note: previous definition of 'xfrm_send_acquire_legacy' was here
    static inline int xfrm_send_acquire_legacy(struct xfrm_state *x,
                      ^~~~~~~~~~~~~~~~~~~~~~~~
>> net/xfrm/xfrm_user_legacy.c:1043:5: error: redefinition of 'xfrm_exp_policy_notify_legacy'
    int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from net/xfrm/xfrm_user_legacy.c:30:0:
   net/xfrm/xfrm_user.h:150:19: note: previous definition of 'xfrm_exp_policy_notify_legacy' was here
    static inline int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> net/xfrm/xfrm_user_legacy.c:1060:5: error: redefinition of 'xfrm_notify_policy_legacy'
    int xfrm_notify_policy_legacy(const struct xfrm_policy *xp,
        ^~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from net/xfrm/xfrm_user_legacy.c:30:0:
   net/xfrm/xfrm_user.h:157:19: note: previous definition of 'xfrm_notify_policy_legacy' was here
    static inline int xfrm_notify_policy_legacy(const struct xfrm_policy *xp,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~

vim +/xfrm_exp_state_notify_legacy +845 net/xfrm/xfrm_user_legacy.c

   839			return err;
   840	
   841		nlmsg_end(skb, nlh);
   842		return 0;
   843	}
   844	
 > 845	int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
   846					 const struct km_event *c)
   847	{
   848		struct net *net = xs_net(x);
   849		struct sk_buff *skb;
   850	
   851		skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
   852		if (skb == NULL)
   853			return -ENOMEM;
   854	
   855		if (build_expire(skb, x, c) < 0) {
   856			kfree_skb(skb);
   857			return -EMSGSIZE;
   858		}
   859	
   860		return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
   861	}
   862	
 > 863	int xfrm_notify_sa_legacy(const struct xfrm_state *x, const struct km_event *c)
   864	{
   865		struct net *net = xs_net(x);
   866		struct xfrm_usersa_info_legacy *p;
   867		struct xfrm_usersa_id *id;
   868		struct nlmsghdr *nlh;
   869		struct sk_buff *skb;
   870		int len = xfrm_sa_len(x);
   871		int headlen, err;
   872		u32 event = 0;
   873	
   874		headlen = sizeof(*p);
   875		if (c->event == XFRM_MSG_DELSA) {
   876			len += nla_total_size(headlen);
   877			headlen = sizeof(*id);
   878			len += nla_total_size(sizeof(struct xfrm_mark));
   879		}
   880		len += NLMSG_ALIGN(headlen);
   881	
   882		skb = nlmsg_new(len, GFP_ATOMIC);
   883		if (skb == NULL)
   884			return -ENOMEM;
   885	
   886		switch (c->event) {
   887		case XFRM_MSG_NEWSA:
   888			event = XFRM_MSG_NEWSA_LEGACY;
   889			break;
   890		case XFRM_MSG_UPDSA:
   891			event = XFRM_MSG_UPDSA_LEGACY;
   892			break;
   893		case XFRM_MSG_DELSA:
   894			event = XFRM_MSG_DELSA_LEGACY;
   895			break;
   896		}
   897	
   898		nlh = nlmsg_put(skb, c->portid, c->seq, event, headlen, 0);
   899		err = -EMSGSIZE;
   900		if (nlh == NULL)
   901			goto out_free_skb;
   902	
   903		p = nlmsg_data(nlh);
   904		if (c->event == XFRM_MSG_DELSA) {
   905			struct nlattr *attr;
   906	
   907			id = nlmsg_data(nlh);
   908			memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
   909			id->spi = x->id.spi;
   910			id->family = x->props.family;
   911			id->proto = x->id.proto;
   912	
   913			attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));
   914			err = -EMSGSIZE;
   915			if (attr == NULL)
   916				goto out_free_skb;
   917	
   918			p = nla_data(attr);
   919		}
   920		err = copy_to_user_state_extra(x, p, skb);
   921		if (err)
   922			goto out_free_skb;
   923	
   924		nlmsg_end(skb, nlh);
   925	
   926		return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA);
   927	
   928	out_free_skb:
   929		kfree_skb(skb);
   930		return err;
   931	}
   932	
   933	static inline size_t xfrm_acquire_msgsize(const struct xfrm_state *x,
   934						  const struct xfrm_policy *xp)
   935	{
   936		return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire_legacy))
   937		       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
   938		       + nla_total_size(sizeof(struct xfrm_mark))
   939		       + nla_total_size(xfrm_user_sec_ctx_size(x->security))
   940		       + userpolicy_type_attrsize();
   941	}
   942	
   943	static int build_acquire(struct sk_buff *skb,
   944				 struct xfrm_state *x,
   945				 const struct xfrm_tmpl *xt,
   946				 const struct xfrm_policy *xp)
   947	{
   948		__u32 seq = xfrm_get_acqseq();
   949		struct xfrm_user_acquire_legacy *ua;
   950		struct nlmsghdr *nlh;
   951		int err;
   952	
   953		nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE_LEGACY, sizeof(*ua), 0);
   954		if (nlh == NULL)
   955			return -EMSGSIZE;
   956	
   957		ua = nlmsg_data(nlh);
   958		memcpy(&ua->id, &x->id, sizeof(ua->id));
   959		memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
   960		memcpy(&ua->sel, &x->sel, sizeof(ua->sel));
   961		copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT);
   962		ua->aalgos = xt->aalgos;
   963		ua->ealgos = xt->ealgos;
   964		ua->calgos = xt->calgos;
   965		ua->seq = x->km.seq = seq;
   966	
   967		err = xfrm_copy_to_user_tmpl(xp, skb);
   968		if (!err)
   969			err = copy_to_user_state_sec_ctx(x, skb);
   970		if (!err)
   971			err = copy_to_user_policy_type(xp->type, skb);
   972		if (!err)
   973			err = xfrm_mark_put(skb, &xp->mark);
   974		if (err) {
   975			nlmsg_cancel(skb, nlh);
   976			return err;
   977		}
   978	
   979		nlmsg_end(skb, nlh);
   980		return 0;
   981	}
   982	
 > 983	int xfrm_send_acquire_legacy(struct xfrm_state *x,
   984				     const struct xfrm_tmpl *xt,
   985				     const struct xfrm_policy *xp)
   986	{
   987		struct net *net = xs_net(x);
   988		struct sk_buff *skb;
   989	
   990		skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
   991		if (skb == NULL)
   992			return -ENOMEM;
   993	
   994		if (build_acquire(skb, x, xt, xp) < 0)
   995			BUG();
   996	
   997		return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
   998	}
   999	
  1000	static inline size_t xfrm_polexpire_msgsize(const struct xfrm_policy *xp)
  1001	{
  1002		return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire_legacy))
  1003		       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
  1004		       + nla_total_size(xfrm_user_sec_ctx_size(xp->security))
  1005		       + nla_total_size(sizeof(struct xfrm_mark))
  1006		       + userpolicy_type_attrsize();
  1007	}
  1008	
  1009	static int build_polexpire(struct sk_buff *skb,
  1010				   const struct xfrm_policy *xp,
  1011				   int dir,
  1012				   const struct km_event *c)
  1013	{
  1014		struct xfrm_user_polexpire_legacy *upe;
  1015		int hard = c->data.hard;
  1016		struct nlmsghdr *nlh;
  1017		int err;
  1018	
  1019		nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE_LEGACY,
  1020				sizeof(*upe), 0);
  1021		if (nlh == NULL)
  1022			return -EMSGSIZE;
  1023	
  1024		upe = nlmsg_data(nlh);
  1025		copy_to_user_policy(xp, &upe->pol, dir);
  1026		err = xfrm_copy_to_user_tmpl(xp, skb);
  1027		if (!err)
  1028			err = copy_to_user_sec_ctx(xp, skb);
  1029		if (!err)
  1030			err = copy_to_user_policy_type(xp->type, skb);
  1031		if (!err)
  1032			err = xfrm_mark_put(skb, &xp->mark);
  1033		if (err) {
  1034			nlmsg_cancel(skb, nlh);
  1035			return err;
  1036		}
  1037		upe->hard = !!hard;
  1038	
  1039		nlmsg_end(skb, nlh);
  1040		return 0;
  1041	}
  1042	
> 1043	int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
  1044					  int dir,
  1045					  const struct km_event *c)
  1046	{

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 45848 bytes --]

^ permalink raw reply

* [RESEND PATCH net] macsec: fix validation failed in asynchronous operation.
From: Ryder Lee @ 2017-01-21  8:42 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Sabrina Dubroca, linux-mediatek, Ryder Lee

Add missing "macsec_skb_cb(skb)->valid = true" in callback
function macsec_decrypt_done(), this fixes packet validation
failed while decrypting asynchronously.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/macsec.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index f83cf66..73d8d39 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -880,6 +880,9 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err)
 	aead_request_free(macsec_skb_cb(skb)->req);
 
 	rcu_read_lock_bh();
+	if (err == 0)
+		macsec_skb_cb(skb)->valid = true;
+
 	pn = ntohl(macsec_ethhdr(skb)->packet_number);
 	if (!macsec_post_decrypt(skb, &macsec->secy, pn)) {
 		rcu_read_unlock_bh();
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH cumulus-4.1.y 1/5] vxlan: flush fdb entries on oper down
From: kbuild test robot @ 2017-01-21  8:54 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: kbuild-all, davem, netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

[-- Attachment #1: Type: text/plain, Size: 1551 bytes --]

Hi Balakrishnan,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Roopa-Prabhu/vxlan-flush-fdb-entries-on-oper-down/20170121-163042
config: x86_64-randconfig-x017-201703 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/net/vxlan.c: In function 'vxlan_netdevice_event':
>> drivers/net/vxlan.c:3280:27: error: 'vxlan_netdev_ops' undeclared (first use in this function)
      if (dev->netdev_ops == &vxlan_netdev_ops) {
                              ^~~~~~~~~~~~~~~~
   drivers/net/vxlan.c:3280:27: note: each undeclared identifier is reported only once for each function it appears in

vim +/vxlan_netdev_ops +3280 drivers/net/vxlan.c

  3274	
  3275		if (event == NETDEV_UNREGISTER)
  3276			vxlan_handle_lowerdev_unregister(vn, dev);
  3277		else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
  3278			vxlan_push_rx_ports(dev);
  3279		else if (event == NETDEV_CHANGE) {
> 3280			if (dev->netdev_ops == &vxlan_netdev_ops) {
  3281				if (netif_running(dev) && !netif_oper_up(dev))
  3282					vxlan_flush(netdev_priv(dev));
  3283			}

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27495 bytes --]

^ permalink raw reply

* Re: [PATCH cumulus-4.1.y 1/5] vxlan: flush fdb entries on oper down
From: kbuild test robot @ 2017-01-21  8:58 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: kbuild-all, davem, netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-1-git-send-email-roopa@cumulusnetworks.com>

[-- Attachment #1: Type: text/plain, Size: 2760 bytes --]

Hi Balakrishnan,

[auto build test WARNING on net-next/master]
[also build test WARNING on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Roopa-Prabhu/vxlan-flush-fdb-entries-on-oper-down/20170121-163042
config: i386-randconfig-x005-201703 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from include/linux/linkage.h:4:0,
                    from include/linux/kernel.h:6,
                    from drivers/net/vxlan.c:13:
   drivers/net/vxlan.c: In function 'vxlan_netdevice_event':
   drivers/net/vxlan.c:3280:27: error: 'vxlan_netdev_ops' undeclared (first use in this function)
      if (dev->netdev_ops == &vxlan_netdev_ops) {
                              ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers/net/vxlan.c:3280:3: note: in expansion of macro 'if'
      if (dev->netdev_ops == &vxlan_netdev_ops) {
      ^~
   drivers/net/vxlan.c:3280:27: note: each undeclared identifier is reported only once for each function it appears in
      if (dev->netdev_ops == &vxlan_netdev_ops) {
                              ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> drivers/net/vxlan.c:3280:3: note: in expansion of macro 'if'
      if (dev->netdev_ops == &vxlan_netdev_ops) {
      ^~

vim +/if +3280 drivers/net/vxlan.c

  3264		}
  3265	
  3266		unregister_netdevice_many(&list_kill);
  3267	}
  3268	
  3269	static int vxlan_netdevice_event(struct notifier_block *unused,
  3270					 unsigned long event, void *ptr)
  3271	{
  3272		struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  3273		struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
  3274	
  3275		if (event == NETDEV_UNREGISTER)
  3276			vxlan_handle_lowerdev_unregister(vn, dev);
  3277		else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
  3278			vxlan_push_rx_ports(dev);
  3279		else if (event == NETDEV_CHANGE) {
> 3280			if (dev->netdev_ops == &vxlan_netdev_ops) {
  3281				if (netif_running(dev) && !netif_oper_up(dev))
  3282					vxlan_flush(netdev_priv(dev));
  3283			}
  3284		}
  3285	
  3286		return NOTIFY_DONE;
  3287	}
  3288	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 29748 bytes --]

^ permalink raw reply

* Re: [PATCH cumulus-4.1.y 4/5] vxlan: don't flush static fdb entries on admin down
From: kbuild test robot @ 2017-01-21  9:25 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: kbuild-all, davem, netdev, ramanb, stephen, jbenc, pshelar
In-Reply-To: <1484984410-3304-4-git-send-email-roopa@cumulusnetworks.com>

[-- Attachment #1: Type: text/plain, Size: 2613 bytes --]

Hi Roopa,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Roopa-Prabhu/vxlan-flush-fdb-entries-on-oper-down/20170121-163042
config: x86_64-randconfig-x017-201703 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/net/vxlan.c: In function 'vxlan_netdevice_event':
   drivers/net/vxlan.c:3295:27: error: 'vxlan_netdev_ops' undeclared (first use in this function)
      if (dev->netdev_ops == &vxlan_netdev_ops) {
                              ^~~~~~~~~~~~~~~~
   drivers/net/vxlan.c:3295:27: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/net/vxlan.c:3297:5: error: too few arguments to function 'vxlan_flush'
        vxlan_flush(netdev_priv(dev));
        ^~~~~~~~~~~
   drivers/net/vxlan.c:2368:13: note: declared here
    static void vxlan_flush(struct vxlan_dev *vxlan, int do_all)
                ^~~~~~~~~~~

vim +/vxlan_flush +3297 drivers/net/vxlan.c

acaf4e7099 Daniel Borkmann      2014-01-13  3289  
783c146335 Daniel Borkmann      2014-01-22  3290  	if (event == NETDEV_UNREGISTER)
acaf4e7099 Daniel Borkmann      2014-01-13  3291  		vxlan_handle_lowerdev_unregister(vn, dev);
7c46a640de Alexander Duyck      2016-06-16  3292  	else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
b7aade1548 Hannes Frederic Sowa 2016-04-18  3293  		vxlan_push_rx_ports(dev);
d8ef10fd7d Balakrishnan Raman   2017-01-20  3294  	else if (event == NETDEV_CHANGE) {
d8ef10fd7d Balakrishnan Raman   2017-01-20 @3295  		if (dev->netdev_ops == &vxlan_netdev_ops) {
d8ef10fd7d Balakrishnan Raman   2017-01-20  3296  			if (netif_running(dev) && !netif_oper_up(dev))
d8ef10fd7d Balakrishnan Raman   2017-01-20 @3297  				vxlan_flush(netdev_priv(dev));
d8ef10fd7d Balakrishnan Raman   2017-01-20  3298  		}
d8ef10fd7d Balakrishnan Raman   2017-01-20  3299  	}
acaf4e7099 Daniel Borkmann      2014-01-13  3300  

:::::: The code at line 3297 was first introduced by commit
:::::: d8ef10fd7d083cc5551d83db6317a692fee076ba vxlan: flush fdb entries on oper down

:::::: TO: Balakrishnan Raman <ramanb@cumulusnetworks.com>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27495 bytes --]

^ permalink raw reply

* (unknown), 
From: tomsue2000 @ 2017-01-21  9:56 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: EMAIL_9865442338_netdev.zip --]
[-- Type: application/zip, Size: 2646 bytes --]

^ permalink raw reply

* [PATCHv5 net-next 0/5] sctp: add sender-side procedures for stream reconf asoc reset and add streams
From: Xin Long @ 2017-01-21 10:24 UTC (permalink / raw)
  To: network dev, linux-sctp
  Cc: Marcelo Ricardo Leitner, Neil Horman, Vlad Yasevich, davem

Patch 3/5 is to implement sender-side procedures for the SSN/TSN Reset
Request Parameter described in rfc6525 section 5.1.4, patch 2/5 is
ahead of it to define a function to make the request chunk for it.

Patch 5/5 is to implement sender-side procedures for the Add Incoming
and Outgoing Streams Request Parameter Request Parameter described in
rfc6525 section 5.1.5 and 5.1.6, patch 4/5 is ahead of it to define a
function to make the request chunk for it.

Patch 1/5 is a fix to recover streams states when it fails to send
request.

v1->v2:
  - put these into a smaller group.
  - rename some temporary variables in the codes.
  - rename the titles of the commits and improve some changelogs.
v2->v3:
  - re-split the patchset and make sure it has no dead codes for review.
  - move some codes into stream.c from socket.c.
v3->v4:
  - add one more patch to fix a send reset stream request issue.
  - doing actual work only when request is sent successfully.
  - reduce some indents in sctp_send_add_streams.
v4->v5:
  - close streams before sending request and recover them when sending
    fails in patch 1/5 and patch 3/5

Xin Long (5):
  sctp: streams should be recovered when it fails to send request.
  sctp: add support for generating stream reconf ssn/tsn reset request
    chunk
  sctp: implement sender-side procedures for SSN/TSN Reset Request
    Parameter
  sctp: add support for generating stream reconf add incoming/outgoing
    streams request chunk
  sctp: implement sender-side procedures for Add Incoming/Outgoing
    Streams Request Parameter

 include/linux/sctp.h      |  12 ++++
 include/net/sctp/sctp.h   |   3 +
 include/net/sctp/sm.h     |   5 ++
 include/uapi/linux/sctp.h |   8 +++
 net/sctp/sm_make_chunk.c  |  75 +++++++++++++++++++++++++
 net/sctp/socket.c         |  58 +++++++++++++++++++
 net/sctp/stream.c         | 138 +++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 298 insertions(+), 1 deletion(-)

-- 
2.1.0

^ permalink raw reply

* [PATCHv5 net-next 1/5] sctp: streams should be recovered when it fails to send request.
From: Xin Long @ 2017-01-21 10:24 UTC (permalink / raw)
  To: network dev, linux-sctp
  Cc: Marcelo Ricardo Leitner, Neil Horman, Vlad Yasevich, davem
In-Reply-To: <cover.1484993773.git.lucien.xin@gmail.com>

Now when sending stream reset request, it closes the streams to
block further xmit of data until this request is completed, then
calls sctp_send_reconf to send the chunk.

But if sctp_send_reconf returns err, and it doesn't recover the
streams' states back,  which means the request chunk would not be
queued and sent, so the asoc will get stuck, streams are closed
and no packet is even queued.

This patch is to fix it by recovering the streams' states when
it fails to send the request, it is also to fix a return value.

Fixes: 7f9d68ac944e ("sctp: implement sender-side procedures for SSN Reset Request Parameter")
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 net/sctp/stream.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 13d5e07..6a686e3 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -136,8 +136,10 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
 				goto out;
 
 	chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
-	if (!chunk)
+	if (!chunk) {
+		retval = -ENOMEM;
 		goto out;
+	}
 
 	if (out) {
 		if (str_nums)
@@ -149,7 +151,6 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
 				stream->out[i].state = SCTP_STREAM_CLOSED;
 	}
 
-	asoc->strreset_outstanding = out + in;
 	asoc->strreset_chunk = chunk;
 	sctp_chunk_hold(asoc->strreset_chunk);
 
@@ -157,8 +158,22 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
 	if (retval) {
 		sctp_chunk_put(asoc->strreset_chunk);
 		asoc->strreset_chunk = NULL;
+		if (!out)
+			goto out;
+
+		if (str_nums)
+			for (i = 0; i < str_nums; i++)
+				stream->out[str_list[i]].state =
+						       SCTP_STREAM_OPEN;
+		else
+			for (i = 0; i < stream->outcnt; i++)
+				stream->out[i].state = SCTP_STREAM_OPEN;
+
+		goto out;
 	}
 
+	asoc->strreset_outstanding = out + in;
+
 out:
 	return retval;
 }
-- 
2.1.0

^ permalink raw reply related

* [PATCHv5 net-next 2/5] sctp: add support for generating stream reconf ssn/tsn reset request chunk
From: Xin Long @ 2017-01-21 10:24 UTC (permalink / raw)
  To: network dev, linux-sctp
  Cc: Marcelo Ricardo Leitner, Neil Horman, Vlad Yasevich, davem
In-Reply-To: <cover.1484993773.git.lucien.xin@gmail.com>

This patch is to define SSN/TSN Reset Request Parameter described
in rfc6525 section 4.3.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/linux/sctp.h     |  5 +++++
 include/net/sctp/sm.h    |  2 ++
 net/sctp/sm_make_chunk.c | 29 +++++++++++++++++++++++++++++
 3 files changed, 36 insertions(+)

diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index a9e7906..95b8ed3 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -737,4 +737,9 @@ struct sctp_strreset_inreq {
 	__u16 list_of_streams[0];
 } __packed;
 
+struct sctp_strreset_tsnreq {
+	sctp_paramhdr_t param_hdr;
+	__u32 request_seq;
+} __packed;
+
 #endif /* __LINUX_SCTP_H__ */
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 430ed13..ac37c17 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -265,6 +265,8 @@ struct sctp_chunk *sctp_make_strreset_req(
 				const struct sctp_association *asoc,
 				__u16 stream_num, __u16 *stream_list,
 				bool out, bool in);
+struct sctp_chunk *sctp_make_strreset_tsnreq(
+				const struct sctp_association *asoc);
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index ad3445b..801450c 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -3660,3 +3660,32 @@ struct sctp_chunk *sctp_make_strreset_req(
 
 	return retval;
 }
+
+/* RE-CONFIG 4.3 (SSN/TSN RESET ALL)
+ *   0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |     Parameter Type = 15       |      Parameter Length = 8     |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |         Re-configuration Request Sequence Number              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct sctp_chunk *sctp_make_strreset_tsnreq(
+				const struct sctp_association *asoc)
+{
+	struct sctp_strreset_tsnreq tsnreq;
+	__u16 length = sizeof(tsnreq);
+	struct sctp_chunk *retval;
+
+	retval = sctp_make_reconf(asoc, length);
+	if (!retval)
+		return NULL;
+
+	tsnreq.param_hdr.type = SCTP_PARAM_RESET_TSN_REQUEST;
+	tsnreq.param_hdr.length = htons(length);
+	tsnreq.request_seq = htonl(asoc->strreset_outseq);
+
+	sctp_addto_chunk(retval, sizeof(tsnreq), &tsnreq);
+
+	return retval;
+}
-- 
2.1.0

^ permalink raw reply related

* [PATCHv5 net-next 3/5] sctp: implement sender-side procedures for SSN/TSN Reset Request Parameter
From: Xin Long @ 2017-01-21 10:24 UTC (permalink / raw)
  To: network dev, linux-sctp
  Cc: Marcelo Ricardo Leitner, Neil Horman, Vlad Yasevich, davem
In-Reply-To: <cover.1484993773.git.lucien.xin@gmail.com>

This patch is to implement Sender-Side Procedures for the SSN/TSN
Reset Request Parameter descibed in rfc6525 section 5.1.4.

It is also to add sockopt SCTP_RESET_ASSOC in rfc6525 section 6.3.3
for users.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/sctp.h   |  1 +
 include/uapi/linux/sctp.h |  1 +
 net/sctp/socket.c         | 29 +++++++++++++++++++++++++++++
 net/sctp/stream.c         | 40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 71 insertions(+)

diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 3cfd365b..b93820f 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -198,6 +198,7 @@ int sctp_offload_init(void);
  */
 int sctp_send_reset_streams(struct sctp_association *asoc,
 			    struct sctp_reset_streams *params);
+int sctp_send_reset_assoc(struct sctp_association *asoc);
 
 /*
  * Module global variables
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 03c27ce..c0bd8c3 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -117,6 +117,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_PR_ASSOC_STATUS	115
 #define SCTP_ENABLE_STREAM_RESET	118
 #define SCTP_RESET_STREAMS	119
+#define SCTP_RESET_ASSOC	120
 
 /* PR-SCTP policies */
 #define SCTP_PR_SCTP_NONE	0x0000
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index bee4dd3..2c5c9ca 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3812,6 +3812,32 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
 	return retval;
 }
 
+static int sctp_setsockopt_reset_assoc(struct sock *sk,
+				       char __user *optval,
+				       unsigned int optlen)
+{
+	struct sctp_association *asoc;
+	sctp_assoc_t associd;
+	int retval = -EINVAL;
+
+	if (optlen != sizeof(associd))
+		goto out;
+
+	if (copy_from_user(&associd, optval, optlen)) {
+		retval = -EFAULT;
+		goto out;
+	}
+
+	asoc = sctp_id2assoc(sk, associd);
+	if (!asoc)
+		goto out;
+
+	retval = sctp_send_reset_assoc(asoc);
+
+out:
+	return retval;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3984,6 +4010,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
 	case SCTP_RESET_STREAMS:
 		retval = sctp_setsockopt_reset_streams(sk, optval, optlen);
 		break;
+	case SCTP_RESET_ASSOC:
+		retval = sctp_setsockopt_reset_assoc(sk, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 6a686e3..53e49fc 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -177,3 +177,43 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
 out:
 	return retval;
 }
+
+int sctp_send_reset_assoc(struct sctp_association *asoc)
+{
+	struct sctp_chunk *chunk = NULL;
+	int retval;
+	__u16 i;
+
+	if (!asoc->peer.reconf_capable ||
+	    !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
+		return -ENOPROTOOPT;
+
+	if (asoc->strreset_outstanding)
+		return -EINPROGRESS;
+
+	chunk = sctp_make_strreset_tsnreq(asoc);
+	if (!chunk)
+		return -ENOMEM;
+
+	/* Block further xmit of data until this request is completed */
+	for (i = 0; i < asoc->stream->outcnt; i++)
+		asoc->stream->out[i].state = SCTP_STREAM_CLOSED;
+
+	asoc->strreset_chunk = chunk;
+	sctp_chunk_hold(asoc->strreset_chunk);
+
+	retval = sctp_send_reconf(asoc, chunk);
+	if (retval) {
+		sctp_chunk_put(asoc->strreset_chunk);
+		asoc->strreset_chunk = NULL;
+
+		for (i = 0; i < asoc->stream->outcnt; i++)
+			asoc->stream->out[i].state = SCTP_STREAM_OPEN;
+
+		return retval;
+	}
+
+	asoc->strreset_outstanding = 1;
+
+	return 0;
+}
-- 
2.1.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox