ipq806x: NSS Hardware Offloading qdisc patches
This commit is contained in:
		| @@ -0,0 +1,44 @@ | |||||||
|  | --- a/include/linux/skbuff.h | ||||||
|  | +++ b/include/linux/skbuff.h | ||||||
|  | @@ -687,6 +687,7 @@ typedef unsigned char *sk_buff_data_t; | ||||||
|  |   *	@offload_fwd_mark: Packet was L2-forwarded in hardware | ||||||
|  |   *	@offload_l3_fwd_mark: Packet was L3-forwarded in hardware | ||||||
|  |   *	@tc_skip_classify: do not classify packet. set by IFB device | ||||||
|  | + *	@tc_skip_classify_offload: do not classify packet set by offload IFB device | ||||||
|  |   *	@tc_at_ingress: used within tc_classify to distinguish in/egress | ||||||
|  |   *	@redirected: packet was redirected by packet classifier | ||||||
|  |   *	@from_ingress: packet was redirected from the ingress path | ||||||
|  | @@ -902,6 +903,8 @@ struct sk_buff { | ||||||
|  |  #ifdef CONFIG_NET_CLS_ACT | ||||||
|  |  	__u8			tc_skip_classify:1; | ||||||
|  |  	__u8			tc_at_ingress:1; | ||||||
|  | +	__u8			tc_skip_classify_offload:1; | ||||||
|  | +	__u16			tc_verd_qca_nss; /* QCA NSS Qdisc Support */ | ||||||
|  |  #endif | ||||||
|  |  	__u8			redirected:1; | ||||||
|  |  #ifdef CONFIG_NET_REDIRECT | ||||||
|  | --- a/include/uapi/linux/pkt_cls.h | ||||||
|  | +++ b/include/uapi/linux/pkt_cls.h | ||||||
|  | @@ -136,6 +136,7 @@ enum tca_id { | ||||||
|  |  	TCA_ID_MPLS, | ||||||
|  |  	TCA_ID_CT, | ||||||
|  |  	TCA_ID_GATE, | ||||||
|  | +	TCA_ID_MIRRED_NSS, /* QCA NSS Qdisc IGS Support */ | ||||||
|  |  	/* other actions go here */ | ||||||
|  |  	__TCA_ID_MAX = 255 | ||||||
|  |  }; | ||||||
|  | @@ -776,4 +777,14 @@ enum { | ||||||
|  |  	TCF_EM_OPND_LT | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +/* QCA NSS Qdisc Support - Start */ | ||||||
|  | +#define _TC_MAKE32(x)		((x)) | ||||||
|  | +#define _TC_MAKEMASK1(n)	(_TC_MAKE32(1) << _TC_MAKE32(n)) | ||||||
|  | + | ||||||
|  | +#define TC_NCLS                 _TC_MAKEMASK1(8) | ||||||
|  | +#define TC_NCLS_NSS		_TC_MAKEMASK1(12) | ||||||
|  | +#define SET_TC_NCLS_NSS(v)	( TC_NCLS_NSS | ((v) & ~TC_NCLS_NSS)) | ||||||
|  | +#define CLR_TC_NCLS_NSS(v)	( (v) & ~TC_NCLS_NSS) | ||||||
|  | +/* QCA NSS Qdisc Support - End */ | ||||||
|  | + | ||||||
|  |  #endif | ||||||
| @@ -0,0 +1,442 @@ | |||||||
|  | --- a/include/linux/timer.h | ||||||
|  | +++ b/include/linux/timer.h | ||||||
|  | @@ -17,6 +17,7 @@ struct timer_list { | ||||||
|  |  	unsigned long		expires; | ||||||
|  |  	void			(*function)(struct timer_list *); | ||||||
|  |  	u32			flags; | ||||||
|  | +	unsigned long		cust_data; | ||||||
|  |   | ||||||
|  |  #ifdef CONFIG_LOCKDEP | ||||||
|  |  	struct lockdep_map	lockdep_map; | ||||||
|  | --- a/drivers/net/ifb.c | ||||||
|  | +++ b/drivers/net/ifb.c | ||||||
|  | @@ -125,6 +125,31 @@ resched: | ||||||
|  |   | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats) | ||||||
|  | +{ | ||||||
|  | +       struct ifb_dev_private *dp; | ||||||
|  | +       struct ifb_q_private *txp; | ||||||
|  | + | ||||||
|  | +       if (!dev || !offload_stats) { | ||||||
|  | +               return; | ||||||
|  | +       } | ||||||
|  | + | ||||||
|  | +       if (!(dev->priv_flags_ext & IFF_EXT_IFB)) { | ||||||
|  | +               return; | ||||||
|  | +       } | ||||||
|  | + | ||||||
|  | +       dp = netdev_priv(dev); | ||||||
|  | +       txp = dp->tx_private; | ||||||
|  | + | ||||||
|  | +       u64_stats_update_begin(&txp->rsync); | ||||||
|  | +       txp->rx_packets += offload_stats->rx_packets; | ||||||
|  | +       txp->rx_bytes += offload_stats->rx_bytes; | ||||||
|  | +       txp->tx_packets += offload_stats->tx_packets; | ||||||
|  | +       txp->tx_bytes += offload_stats->tx_bytes; | ||||||
|  | +       u64_stats_update_end(&txp->rsync); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(ifb_update_offload_stats); | ||||||
|  | + | ||||||
|  |  static void ifb_stats64(struct net_device *dev, | ||||||
|  |  			struct rtnl_link_stats64 *stats) | ||||||
|  |  { | ||||||
|  | @@ -224,6 +249,7 @@ static void ifb_setup(struct net_device | ||||||
|  |  	dev->flags |= IFF_NOARP; | ||||||
|  |  	dev->flags &= ~IFF_MULTICAST; | ||||||
|  |  	dev->priv_flags &= ~IFF_TX_SKB_SHARING; | ||||||
|  | +	dev->priv_flags_ext |= IFF_EXT_IFB;     /* Mark the device as an IFB device. */ | ||||||
|  |  	netif_keep_dst(dev); | ||||||
|  |  	eth_hw_addr_random(dev); | ||||||
|  |  	dev->needs_free_netdev = true; | ||||||
|  | --- a/include/linux/netdevice.h | ||||||
|  | +++ b/include/linux/netdevice.h | ||||||
|  | @@ -4749,6 +4749,15 @@ void dev_uc_flush(struct net_device *dev | ||||||
|  |  void dev_uc_init(struct net_device *dev); | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | + *  ifb_update_offload_stats - Update the IFB interface stats | ||||||
|  | + *  @dev: IFB device to update the stats | ||||||
|  | + *  @offload_stats: per CPU stats structure | ||||||
|  | + * | ||||||
|  | + *  Allows update of IFB stats when flows are offloaded to an accelerator. | ||||||
|  | + **/ | ||||||
|  | +void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats); | ||||||
|  | + | ||||||
|  | +/** | ||||||
|  |   *  __dev_uc_sync - Synchonize device's unicast list | ||||||
|  |   *  @dev:  device to sync | ||||||
|  |   *  @sync: function to call if address should be added | ||||||
|  | @@ -5298,6 +5307,11 @@ static inline bool netif_is_failover_sla | ||||||
|  |  	return dev->priv_flags & IFF_FAILOVER_SLAVE; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static inline bool netif_is_ifb_dev(const struct net_device *dev) | ||||||
|  | +{ | ||||||
|  | +	return dev->priv_flags_ext & IFF_EXT_IFB; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */ | ||||||
|  |  static inline void netif_keep_dst(struct net_device *dev) | ||||||
|  |  { | ||||||
|  | --- a/include/uapi/linux/pkt_sched.h | ||||||
|  | +++ b/include/uapi/linux/pkt_sched.h | ||||||
|  | @@ -1265,4 +1265,248 @@ enum { | ||||||
|  |   | ||||||
|  |  #define TCA_ETS_MAX (__TCA_ETS_MAX - 1) | ||||||
|  |   | ||||||
|  | +/* QCA NSS Clients Support - Start */ | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSS_ACCEL_MODE_NSS_FW, | ||||||
|  | +	TCA_NSS_ACCEL_MODE_PPE, | ||||||
|  | +	TCA_NSS_ACCEL_MODE_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSFIFO section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSFIFO_UNSPEC, | ||||||
|  | +	TCA_NSSFIFO_PARMS, | ||||||
|  | +	__TCA_NSSFIFO_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSFIFO_MAX	(__TCA_NSSFIFO_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nssfifo_qopt { | ||||||
|  | +	__u32	limit;		/* Queue length: bytes for bfifo, packets for pfifo */ | ||||||
|  | +	__u8	set_default;	/* Sets qdisc to be the default qdisc for enqueue */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSWRED section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSWRED_UNSPEC, | ||||||
|  | +	TCA_NSSWRED_PARMS, | ||||||
|  | +	__TCA_NSSWRED_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1) | ||||||
|  | +#define NSSWRED_CLASS_MAX 6 | ||||||
|  | +struct tc_red_alg_parameter { | ||||||
|  | +	__u32	min;	/* qlen_avg < min: pkts are all enqueued */ | ||||||
|  | +	__u32	max;	/* qlen_avg > max: pkts are all dropped */ | ||||||
|  | +	__u32	probability;/* Drop probability at qlen_avg = max */ | ||||||
|  | +	__u32	exp_weight_factor;/* exp_weight_factor for calculate qlen_avg */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsswred_traffic_class { | ||||||
|  | +	__u32 limit;			/* Queue length */ | ||||||
|  | +	__u32 weight_mode_value;	/* Weight mode value */ | ||||||
|  | +	struct tc_red_alg_parameter rap;/* Parameters for RED alg */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * Weight modes for WRED | ||||||
|  | + */ | ||||||
|  | +enum tc_nsswred_weight_modes { | ||||||
|  | +	TC_NSSWRED_WEIGHT_MODE_DSCP = 0,/* Weight mode is DSCP */ | ||||||
|  | +	TC_NSSWRED_WEIGHT_MODES,	/* Must be last */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsswred_qopt { | ||||||
|  | +	__u32	limit;			/* Queue length */ | ||||||
|  | +	enum tc_nsswred_weight_modes weight_mode; | ||||||
|  | +					/* Weight mode */ | ||||||
|  | +	__u32	traffic_classes;	/* How many traffic classes: DPs */ | ||||||
|  | +	__u32	def_traffic_class;	/* Default traffic if no match: def_DP */ | ||||||
|  | +	__u32	traffic_id;		/* The traffic id to be configured: DP */ | ||||||
|  | +	__u32	weight_mode_value;	/* Weight mode value */ | ||||||
|  | +	struct tc_red_alg_parameter rap;/* RED algorithm parameters */ | ||||||
|  | +	struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX]; | ||||||
|  | +					/* Traffic settings for dumpping */ | ||||||
|  | +	__u8	ecn;			/* Setting ECN bit or dropping */ | ||||||
|  | +	__u8	set_default;		/* Sets qdisc to be the default for enqueue */ | ||||||
|  | +	__u8	accel_mode;		/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSCODEL section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSCODEL_UNSPEC, | ||||||
|  | +	TCA_NSSCODEL_PARMS, | ||||||
|  | +	__TCA_NSSCODEL_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSCODEL_MAX	(__TCA_NSSCODEL_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nsscodel_qopt { | ||||||
|  | +	__u32	target;		/* Acceptable queueing delay */ | ||||||
|  | +	__u32	limit;		/* Max number of packets that can be held in the queue */ | ||||||
|  | +	__u32	interval;	/* Monitoring interval */ | ||||||
|  | +	__u32	flows;		/* Number of flow buckets */ | ||||||
|  | +	__u32	quantum;	/* Weight (in bytes) used for DRR of flow buckets */ | ||||||
|  | +	__u8	ecn;		/* 0 - disable ECN, 1 - enable ECN */ | ||||||
|  | +	__u8	set_default;	/* Sets qdisc to be the default qdisc for enqueue */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsscodel_xstats { | ||||||
|  | +	__u32 peak_queue_delay;	/* Peak delay experienced by a dequeued packet */ | ||||||
|  | +	__u32 peak_drop_delay;	/* Peak delay experienced by a dropped packet */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSFQ_CODEL section */ | ||||||
|  | + | ||||||
|  | +struct tc_nssfq_codel_xstats { | ||||||
|  | +	__u32 new_flow_count;	/* Total number of new flows seen */ | ||||||
|  | +	__u32 new_flows_len;	/* Current number of new flows */ | ||||||
|  | +	__u32 old_flows_len;	/* Current number of old flows */ | ||||||
|  | +	__u32 ecn_mark;		/* Number of packets marked with ECN */ | ||||||
|  | +	__u32 drop_overlimit;	/* Number of packets dropped due to overlimit */ | ||||||
|  | +	__u32 maxpacket;	/* The largest packet seen so far in the queue */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSTBL section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSTBL_UNSPEC, | ||||||
|  | +	TCA_NSSTBL_PARMS, | ||||||
|  | +	__TCA_NSSTBL_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSTBL_MAX	(__TCA_NSSTBL_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nsstbl_qopt { | ||||||
|  | +	__u32	burst;		/* Maximum burst size */ | ||||||
|  | +	__u32	rate;		/* Limiting rate of TBF */ | ||||||
|  | +	__u32	peakrate;	/* Maximum rate at which TBF is allowed to send */ | ||||||
|  | +	__u32	mtu;		/* Max size of packet, or minumim burst size */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSPRIO section */ | ||||||
|  | + | ||||||
|  | +#define TCA_NSSPRIO_MAX_BANDS 256 | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSPRIO_UNSPEC, | ||||||
|  | +	TCA_NSSPRIO_PARMS, | ||||||
|  | +	__TCA_NSSPRIO_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSPRIO_MAX	(__TCA_NSSPRIO_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nssprio_qopt { | ||||||
|  | +	__u32	bands;		/* Number of bands */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSBF section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSBF_UNSPEC, | ||||||
|  | +	TCA_NSSBF_CLASS_PARMS, | ||||||
|  | +	TCA_NSSBF_QDISC_PARMS, | ||||||
|  | +	__TCA_NSSBF_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSBF_MAX	(__TCA_NSSBF_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nssbf_class_qopt { | ||||||
|  | +	__u32	burst;		/* Maximum burst size */ | ||||||
|  | +	__u32	rate;		/* Allowed bandwidth for this class */ | ||||||
|  | +	__u32	mtu;		/* MTU of the associated interface */ | ||||||
|  | +	__u32	quantum;	/* Quantum allocation for DRR */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nssbf_qopt { | ||||||
|  | +	__u16	defcls;		/* Default class value */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSWRR section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSWRR_UNSPEC, | ||||||
|  | +	TCA_NSSWRR_CLASS_PARMS, | ||||||
|  | +	TCA_NSSWRR_QDISC_PARMS, | ||||||
|  | +	__TCA_NSSWRR_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSWRR_MAX	(__TCA_NSSWRR_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nsswrr_class_qopt { | ||||||
|  | +	__u32	quantum;	/* Weight associated to this class */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsswrr_qopt { | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSWFQ section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSWFQ_UNSPEC, | ||||||
|  | +	TCA_NSSWFQ_CLASS_PARMS, | ||||||
|  | +	TCA_NSSWFQ_QDISC_PARMS, | ||||||
|  | +	__TCA_NSSWFQ_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSWFQ_MAX	(__TCA_NSSWFQ_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nsswfq_class_qopt { | ||||||
|  | +	__u32	quantum;	/* Weight associated to this class */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsswfq_qopt { | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSHTB section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSHTB_UNSPEC, | ||||||
|  | +	TCA_NSSHTB_CLASS_PARMS, | ||||||
|  | +	TCA_NSSHTB_QDISC_PARMS, | ||||||
|  | +	__TCA_NSSHTB_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSHTB_MAX	(__TCA_NSSHTB_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nsshtb_class_qopt { | ||||||
|  | +	__u32	burst;		/* Allowed burst size */ | ||||||
|  | +	__u32	rate;		/* Allowed bandwidth for this class */ | ||||||
|  | +	__u32	cburst;		/* Maximum burst size */ | ||||||
|  | +	__u32	crate;		/* Maximum bandwidth for this class */ | ||||||
|  | +	__u32	quantum;	/* Quantum allocation for DRR */ | ||||||
|  | +	__u32	priority;	/* Priority value associated with this class */ | ||||||
|  | +	__u32	overhead;	/* Overhead in bytes per packet */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct tc_nsshtb_qopt { | ||||||
|  | +	__u32	r2q;		/* Rate to quantum ratio */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +/* NSSBLACKHOLE section */ | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	TCA_NSSBLACKHOLE_UNSPEC, | ||||||
|  | +	TCA_NSSBLACKHOLE_PARMS, | ||||||
|  | +	__TCA_NSSBLACKHOLE_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define TCA_NSSBLACKHOLE_MAX	(__TCA_NSSBLACKHOLE_MAX - 1) | ||||||
|  | + | ||||||
|  | +struct tc_nssblackhole_qopt { | ||||||
|  | +	__u8	set_default;	/* Sets qdisc to be the default qdisc for enqueue */ | ||||||
|  | +	__u8	accel_mode;	/* Dictates which data plane offloads the qdisc */ | ||||||
|  | +}; | ||||||
|  | +/* QCA NSS Clients Support - End */ | ||||||
|  |  #endif | ||||||
|  | --- a/net/sched/sch_api.c | ||||||
|  | +++ b/net/sched/sch_api.c | ||||||
|  | @@ -2304,4 +2304,26 @@ static int __init pktsched_init(void) | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* QCA NSS Qdisc Support - Start */ | ||||||
|  | +bool tcf_destroy(struct tcf_proto *tp, bool force) | ||||||
|  | +{ | ||||||
|  | +	tp->ops->destroy(tp, force, NULL); | ||||||
|  | +	module_put(tp->ops->owner); | ||||||
|  | +	kfree_rcu(tp, rcu); | ||||||
|  | + | ||||||
|  | +	return true; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void tcf_destroy_chain(struct tcf_proto __rcu **fl) | ||||||
|  | +{ | ||||||
|  | +	struct tcf_proto *tp; | ||||||
|  | + | ||||||
|  | +	while ((tp = rtnl_dereference(*fl)) != NULL) { | ||||||
|  | +		RCU_INIT_POINTER(*fl, tp->next); | ||||||
|  | +		tcf_destroy(tp, true); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(tcf_destroy_chain); | ||||||
|  | +/* QCA NSS Qdisc Support - End */ | ||||||
|  | + | ||||||
|  |  subsys_initcall(pktsched_init); | ||||||
|  | --- a/net/sched/sch_generic.c | ||||||
|  | +++ b/net/sched/sch_generic.c | ||||||
|  | @@ -1008,7 +1008,7 @@ static void qdisc_free_cb(struct rcu_hea | ||||||
|  |  	qdisc_free(q); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static void qdisc_destroy(struct Qdisc *qdisc) | ||||||
|  | +void qdisc_destroy(struct Qdisc *qdisc) | ||||||
|  |  { | ||||||
|  |  	const struct Qdisc_ops  *ops = qdisc->ops; | ||||||
|  |   | ||||||
|  | @@ -1031,6 +1031,7 @@ static void qdisc_destroy(struct Qdisc * | ||||||
|  |   | ||||||
|  |  	call_rcu(&qdisc->rcu, qdisc_free_cb); | ||||||
|  |  } | ||||||
|  | +EXPORT_SYMBOL(qdisc_destroy); | ||||||
|  |   | ||||||
|  |  void qdisc_put(struct Qdisc *qdisc) | ||||||
|  |  { | ||||||
|  | --- a/include/net/sch_generic.h | ||||||
|  | +++ b/include/net/sch_generic.h | ||||||
|  | @@ -87,6 +87,7 @@ struct Qdisc { | ||||||
|  |  #define TCQ_F_INVISIBLE		0x80 /* invisible by default in dump */ | ||||||
|  |  #define TCQ_F_NOLOCK		0x100 /* qdisc does not require locking */ | ||||||
|  |  #define TCQ_F_OFFLOADED		0x200 /* qdisc is offloaded to HW */ | ||||||
|  | +#define TCQ_F_NSS		0x1000 /* NSS qdisc flag. */ | ||||||
|  |  	u32			limit; | ||||||
|  |  	const struct Qdisc_ops	*ops; | ||||||
|  |  	struct qdisc_size_table	__rcu *stab; | ||||||
|  | @@ -738,6 +739,40 @@ static inline bool skb_skip_tc_classify( | ||||||
|  |  	return false; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* | ||||||
|  | + * Set skb classify bit field. | ||||||
|  | + */ | ||||||
|  | +static inline void skb_set_tc_classify_offload(struct sk_buff *skb) | ||||||
|  | +{ | ||||||
|  | +#ifdef CONFIG_NET_CLS_ACT | ||||||
|  | +	skb->tc_skip_classify_offload = 1; | ||||||
|  | +#endif | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * Clear skb classify bit field. | ||||||
|  | + */ | ||||||
|  | +static inline void skb_clear_tc_classify_offload(struct sk_buff *skb) | ||||||
|  | +{ | ||||||
|  | +#ifdef CONFIG_NET_CLS_ACT | ||||||
|  | +	skb->tc_skip_classify_offload = 0; | ||||||
|  | +#endif | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * Skip skb processing if sent from ifb dev. | ||||||
|  | + */ | ||||||
|  | +static inline bool skb_skip_tc_classify_offload(struct sk_buff *skb) | ||||||
|  | +{ | ||||||
|  | +#ifdef CONFIG_NET_CLS_ACT | ||||||
|  | +	if (skb->tc_skip_classify_offload) { | ||||||
|  | +		skb_clear_tc_classify_offload(skb); | ||||||
|  | +		return true; | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +	return false; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* Reset all TX qdiscs greater than index of a device.  */ | ||||||
|  |  static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) | ||||||
|  |  { | ||||||
|  | @@ -1336,4 +1371,9 @@ void mini_qdisc_pair_block_init(struct m | ||||||
|  |   | ||||||
|  |  int sch_frag_xmit_hook(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb)); | ||||||
|  |   | ||||||
|  | +/* QCA NSS Qdisc Support - Start */ | ||||||
|  | +void qdisc_destroy(struct Qdisc *qdisc); | ||||||
|  | +void tcf_destroy_chain(struct tcf_proto __rcu **fl); | ||||||
|  | +/* QCA NSS Qdisc Support - End */ | ||||||
|  | + | ||||||
|  |  #endif | ||||||
| @@ -0,0 +1,46 @@ | |||||||
|  | --- a/net/l2tp/l2tp_core.c | ||||||
|  | +++ b/net/l2tp/l2tp_core.c | ||||||
|  | @@ -400,6 +400,31 @@ err_tlock: | ||||||
|  |  } | ||||||
|  |  EXPORT_SYMBOL_GPL(l2tp_session_register); | ||||||
|  |   | ||||||
|  | +void l2tp_stats_update(struct l2tp_tunnel *tunnel, | ||||||
|  | +                       struct l2tp_session *session, | ||||||
|  | +                       struct l2tp_stats *stats) | ||||||
|  | +{ | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->rx_packets), | ||||||
|  | +                        &tunnel->stats.rx_packets); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->rx_bytes), | ||||||
|  | +                        &tunnel->stats.rx_bytes); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->tx_packets), | ||||||
|  | +                        &tunnel->stats.tx_packets); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->tx_bytes), | ||||||
|  | +                        &tunnel->stats.tx_bytes); | ||||||
|  | + | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->rx_packets), | ||||||
|  | +                        &session->stats.rx_packets); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->rx_bytes), | ||||||
|  | +                        &session->stats.rx_bytes); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->tx_packets), | ||||||
|  | +                        &session->stats.tx_packets); | ||||||
|  | +        atomic_long_add(atomic_long_read(&stats->tx_bytes), | ||||||
|  | +                        &session->stats.tx_bytes); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL_GPL(l2tp_stats_update); | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  /***************************************************************************** | ||||||
|  |   * Receive data handling | ||||||
|  |   *****************************************************************************/ | ||||||
|  | --- a/net/l2tp/l2tp_core.h | ||||||
|  | +++ b/net/l2tp/l2tp_core.h | ||||||
|  | @@ -232,6 +232,9 @@ struct l2tp_session *l2tp_session_get_nt | ||||||
|  |  struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, | ||||||
|  |  						const char *ifname); | ||||||
|  |   | ||||||
|  | +void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, | ||||||
|  | +                       struct l2tp_stats *stats); | ||||||
|  | + | ||||||
|  |  /* Tunnel and session lifetime management. | ||||||
|  |   * Creation of a new instance is a two-step process: create, then register. | ||||||
|  |   * Destruction is triggered using the *_delete functions, and completes asynchronously. | ||||||
| @@ -0,0 +1,488 @@ | |||||||
|  | --- a/include/linux/if_pppox.h | ||||||
|  | +++ b/include/linux/if_pppox.h | ||||||
|  | @@ -38,6 +38,7 @@ struct pptp_opt { | ||||||
|  |  	u32 ack_sent, ack_recv; | ||||||
|  |  	u32 seq_sent, seq_recv; | ||||||
|  |  	int ppp_flags; | ||||||
|  | +	bool pptp_offload_mode; | ||||||
|  |  }; | ||||||
|  |  #include <net/sock.h> | ||||||
|  |   | ||||||
|  | @@ -102,8 +103,40 @@ struct pppoe_channel_ops { | ||||||
|  |  	int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *); | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +/* PPTP client callback */ | ||||||
|  | +typedef int (*pptp_gre_seq_offload_callback_t)(struct sk_buff *skb, | ||||||
|  | +					       struct net_device *pptp_dev); | ||||||
|  | + | ||||||
|  |  /* Return PPPoE channel specific addressing information */ | ||||||
|  |  extern int pppoe_channel_addressing_get(struct ppp_channel *chan, | ||||||
|  |  					 struct pppoe_opt *addressing); | ||||||
|  |   | ||||||
|  | +/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */ | ||||||
|  | +extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, | ||||||
|  | +			 __be32 daddr, __be32 saddr); | ||||||
|  | + | ||||||
|  | +/* Lookup PPTP session info and return PPTP session using dip and peer call id */ | ||||||
|  | +extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, | ||||||
|  | +			     __be32 peer_ip_addr); | ||||||
|  | + | ||||||
|  | +/* Return PPTP session information given the channel */ | ||||||
|  | +extern void pptp_channel_addressing_get(struct pptp_opt *opt, | ||||||
|  | +					struct ppp_channel *chan); | ||||||
|  | + | ||||||
|  | +/* Enable the PPTP session offload flag */ | ||||||
|  | +extern int pptp_session_enable_offload_mode(__be16 peer_call_id, | ||||||
|  | +					    __be32 peer_ip_addr); | ||||||
|  | + | ||||||
|  | +/* Disable the PPTP session offload flag */ | ||||||
|  | +extern int pptp_session_disable_offload_mode(__be16 peer_call_id, | ||||||
|  | +					     __be32 peer_ip_addr); | ||||||
|  | + | ||||||
|  | +/* Register the PPTP GRE packets sequence number offload callback */ | ||||||
|  | +extern int | ||||||
|  | +pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t | ||||||
|  | +				       pptp_client_cb); | ||||||
|  | + | ||||||
|  | +/* Unregister the PPTP GRE packets sequence number offload callback */ | ||||||
|  | +extern void pptp_unregister_gre_seq_offload_callback(void); | ||||||
|  | + | ||||||
|  |  #endif /* !(__LINUX_IF_PPPOX_H) */ | ||||||
|  | --- a/drivers/net/ppp/ppp_generic.c | ||||||
|  | +++ b/drivers/net/ppp/ppp_generic.c | ||||||
|  | @@ -2970,6 +2970,20 @@ char *ppp_dev_name(struct ppp_channel *c | ||||||
|  |  	return name; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* Return the PPP net device index */ | ||||||
|  | +int ppp_dev_index(struct ppp_channel *chan) | ||||||
|  | +{ | ||||||
|  | +	struct channel *pch = chan->ppp; | ||||||
|  | +	int ifindex = 0; | ||||||
|  | + | ||||||
|  | +	if (pch) { | ||||||
|  | +		read_lock_bh(&pch->upl); | ||||||
|  | +		if (pch->ppp && pch->ppp->dev) | ||||||
|  | +			ifindex = pch->ppp->dev->ifindex; | ||||||
|  | +		read_unlock_bh(&pch->upl); | ||||||
|  | +	} | ||||||
|  | +	return ifindex; | ||||||
|  | +} | ||||||
|  |   | ||||||
|  |  /* | ||||||
|  |   * Disconnect a channel from the generic layer. | ||||||
|  | @@ -3678,6 +3692,28 @@ void ppp_update_stats(struct net_device | ||||||
|  |  	ppp_recv_unlock(ppp); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* Returns true if Compression is enabled on PPP device | ||||||
|  | + */ | ||||||
|  | +bool ppp_is_cp_enabled(struct net_device *dev) | ||||||
|  | +{ | ||||||
|  | +	struct ppp *ppp; | ||||||
|  | +	bool flag = false; | ||||||
|  | + | ||||||
|  | +	if (!dev) | ||||||
|  | +		return false; | ||||||
|  | + | ||||||
|  | +	if (dev->type != ARPHRD_PPP) | ||||||
|  | +		return false; | ||||||
|  | + | ||||||
|  | +	ppp = netdev_priv(dev); | ||||||
|  | +	ppp_lock(ppp); | ||||||
|  | +	flag = !!(ppp->xstate & SC_COMP_RUN) || !!(ppp->rstate & SC_DECOMP_RUN); | ||||||
|  | +	ppp_unlock(ppp); | ||||||
|  | + | ||||||
|  | +	return flag; | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(ppp_is_cp_enabled); | ||||||
|  | + | ||||||
|  |  /* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if | ||||||
|  |   * the device is not PPP. | ||||||
|  |   */ | ||||||
|  | @@ -3869,6 +3905,7 @@ EXPORT_SYMBOL(ppp_unregister_channel); | ||||||
|  |  EXPORT_SYMBOL(ppp_channel_index); | ||||||
|  |  EXPORT_SYMBOL(ppp_unit_number); | ||||||
|  |  EXPORT_SYMBOL(ppp_dev_name); | ||||||
|  | +EXPORT_SYMBOL(ppp_dev_index); | ||||||
|  |  EXPORT_SYMBOL(ppp_input); | ||||||
|  |  EXPORT_SYMBOL(ppp_input_error); | ||||||
|  |  EXPORT_SYMBOL(ppp_output_wakeup); | ||||||
|  | --- a/include/linux/ppp_channel.h | ||||||
|  | +++ b/include/linux/ppp_channel.h | ||||||
|  | @@ -82,6 +82,9 @@ extern void ppp_unregister_channel(struc | ||||||
|  |  /* Get the channel number for a channel */ | ||||||
|  |  extern int ppp_channel_index(struct ppp_channel *); | ||||||
|  |   | ||||||
|  | +/* Get the device index  associated with a channel, or 0, if none */ | ||||||
|  | +extern int ppp_dev_index(struct ppp_channel *); | ||||||
|  | + | ||||||
|  |  /* Get the unit number associated with a channel, or -1 if none */ | ||||||
|  |  extern int ppp_unit_number(struct ppp_channel *); | ||||||
|  |   | ||||||
|  | @@ -114,6 +117,7 @@ extern int ppp_hold_channels(struct net_ | ||||||
|  |  /* Test if ppp xmit lock is locked */ | ||||||
|  |  extern bool ppp_is_xmit_locked(struct net_device *dev); | ||||||
|  |   | ||||||
|  | +bool ppp_is_cp_enabled(struct net_device *dev); | ||||||
|  |  /* Test if the ppp device is a multi-link ppp device */ | ||||||
|  |  extern int ppp_is_multilink(struct net_device *dev); | ||||||
|  |   | ||||||
|  | --- a/drivers/net/ppp/pptp.c | ||||||
|  | +++ b/drivers/net/ppp/pptp.c | ||||||
|  | @@ -49,6 +49,8 @@ static struct proto pptp_sk_proto __read | ||||||
|  |  static const struct ppp_channel_ops pptp_chan_ops; | ||||||
|  |  static const struct proto_ops pptp_ops; | ||||||
|  |   | ||||||
|  | +static pptp_gre_seq_offload_callback_t __rcu pptp_gre_offload_xmit_cb; | ||||||
|  | + | ||||||
|  |  static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr) | ||||||
|  |  { | ||||||
|  |  	struct pppox_sock *sock; | ||||||
|  | @@ -90,6 +92,79 @@ static int lookup_chan_dst(u16 call_id, | ||||||
|  |  	return i < MAX_CALLID; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* Search a pptp session based on local call id, local and remote ip address */ | ||||||
|  | +static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr) | ||||||
|  | +{ | ||||||
|  | +	struct pppox_sock *sock; | ||||||
|  | +	int i = 1; | ||||||
|  | + | ||||||
|  | +	rcu_read_lock(); | ||||||
|  | +	for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { | ||||||
|  | +		sock = rcu_dereference(callid_sock[i]); | ||||||
|  | +		if (!sock) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		if (sock->proto.pptp.src_addr.call_id == call_id && | ||||||
|  | +		    sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr && | ||||||
|  | +		    sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) { | ||||||
|  | +			sock_hold(sk_pppox(sock)); | ||||||
|  | +			memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); | ||||||
|  | +			sock_put(sk_pppox(sock)); | ||||||
|  | +			rcu_read_unlock(); | ||||||
|  | +			return 0; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	rcu_read_unlock(); | ||||||
|  | +	return -EINVAL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* Search a pptp session based on peer call id and peer ip address */ | ||||||
|  | +static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr) | ||||||
|  | +{ | ||||||
|  | +	struct pppox_sock *sock; | ||||||
|  | +	int i = 1; | ||||||
|  | + | ||||||
|  | +	rcu_read_lock(); | ||||||
|  | +	for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { | ||||||
|  | +		sock = rcu_dereference(callid_sock[i]); | ||||||
|  | +		if (!sock) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		if (sock->proto.pptp.dst_addr.call_id == call_id && | ||||||
|  | +		    sock->proto.pptp.dst_addr.sin_addr.s_addr == d_addr) { | ||||||
|  | +			sock_hold(sk_pppox(sock)); | ||||||
|  | +			memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); | ||||||
|  | +			sock_put(sk_pppox(sock)); | ||||||
|  | +			rcu_read_unlock(); | ||||||
|  | +			return 0; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	rcu_read_unlock(); | ||||||
|  | +	return -EINVAL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* If offload mode set then this function sends all packets to | ||||||
|  | + * offload module instead of network stack | ||||||
|  | + */ | ||||||
|  | +static int pptp_client_skb_xmit(struct sk_buff *skb, | ||||||
|  | +				struct net_device *pptp_dev) | ||||||
|  | +{ | ||||||
|  | +	pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	rcu_read_lock(); | ||||||
|  | +	pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); | ||||||
|  | + | ||||||
|  | +	if (!pptp_gre_offload_cb_f) { | ||||||
|  | +		rcu_read_unlock(); | ||||||
|  | +		return -1; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = pptp_gre_offload_cb_f(skb, pptp_dev); | ||||||
|  | +	rcu_read_unlock(); | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int add_chan(struct pppox_sock *sock, | ||||||
|  |  		    struct pptp_addr *sa) | ||||||
|  |  { | ||||||
|  | @@ -145,8 +220,11 @@ static int pptp_xmit(struct ppp_channel | ||||||
|  |   | ||||||
|  |  	struct rtable *rt; | ||||||
|  |  	struct net_device *tdev; | ||||||
|  | +	struct net_device *pptp_dev; | ||||||
|  |  	struct iphdr  *iph; | ||||||
|  |  	int    max_headroom; | ||||||
|  | +	int    pptp_ifindex; | ||||||
|  | +	int    ret; | ||||||
|  |   | ||||||
|  |  	if (sk_pppox(po)->sk_state & PPPOX_DEAD) | ||||||
|  |  		goto tx_error; | ||||||
|  | @@ -155,7 +233,7 @@ static int pptp_xmit(struct ppp_channel | ||||||
|  |  				   opt->dst_addr.sin_addr.s_addr, | ||||||
|  |  				   opt->src_addr.sin_addr.s_addr, | ||||||
|  |  				   0, 0, IPPROTO_GRE, | ||||||
|  | -				   RT_TOS(0), sk->sk_bound_dev_if); | ||||||
|  | +				   RT_TOS(0), 0); | ||||||
|  |  	if (IS_ERR(rt)) | ||||||
|  |  		goto tx_error; | ||||||
|  |   | ||||||
|  | @@ -244,7 +322,32 @@ static int pptp_xmit(struct ppp_channel | ||||||
|  |  	ip_select_ident(net, skb, NULL); | ||||||
|  |  	ip_send_check(iph); | ||||||
|  |   | ||||||
|  | -	ip_local_out(net, skb->sk, skb); | ||||||
|  | +	pptp_ifindex = ppp_dev_index(chan); | ||||||
|  | + | ||||||
|  | +	/* set incoming interface as the ppp interface */ | ||||||
|  | +	if (skb->skb_iif) | ||||||
|  | +		skb->skb_iif = pptp_ifindex; | ||||||
|  | + | ||||||
|  | +	/* If the PPTP GRE seq number offload module is not enabled yet | ||||||
|  | +	 * then sends all PPTP GRE packets through linux network stack | ||||||
|  | +	 */ | ||||||
|  | +	if (!opt->pptp_offload_mode) { | ||||||
|  | +		ip_local_out(net, skb->sk, skb); | ||||||
|  | +		return 1; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	pptp_dev = dev_get_by_index(&init_net, pptp_ifindex); | ||||||
|  | +	if (!pptp_dev) | ||||||
|  | +		goto tx_error; | ||||||
|  | + | ||||||
|  | +	 /* If PPTP offload module is enabled then forward all PPTP GRE | ||||||
|  | +	  * packets to PPTP GRE offload module | ||||||
|  | +	  */ | ||||||
|  | +	ret = pptp_client_skb_xmit(skb, pptp_dev); | ||||||
|  | +	dev_put(pptp_dev); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		goto tx_error; | ||||||
|  | + | ||||||
|  |  	return 1; | ||||||
|  |   | ||||||
|  |  tx_error: | ||||||
|  | @@ -300,6 +403,13 @@ static int pptp_rcv_core(struct sock *sk | ||||||
|  |  		goto drop; | ||||||
|  |   | ||||||
|  |  	payload = skb->data + headersize; | ||||||
|  | + | ||||||
|  | +	 /* If offload is enabled, we expect the offload module | ||||||
|  | +	  * to handle PPTP GRE sequence number checks | ||||||
|  | +	  */ | ||||||
|  | +	if (opt->pptp_offload_mode) | ||||||
|  | +		goto allow_packet; | ||||||
|  | + | ||||||
|  |  	/* check for expected sequence number */ | ||||||
|  |  	if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { | ||||||
|  |  		if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && | ||||||
|  | @@ -357,6 +467,7 @@ static int pptp_rcv(struct sk_buff *skb) | ||||||
|  |  	if (po) { | ||||||
|  |  		skb_dst_drop(skb); | ||||||
|  |  		nf_reset_ct(skb); | ||||||
|  | +		skb->skb_iif = ppp_dev_index(&po->chan); | ||||||
|  |  		return sk_receive_skb(sk_pppox(po), skb, 0); | ||||||
|  |  	} | ||||||
|  |  drop: | ||||||
|  | @@ -442,8 +553,7 @@ static int pptp_connect(struct socket *s | ||||||
|  |  				   opt->dst_addr.sin_addr.s_addr, | ||||||
|  |  				   opt->src_addr.sin_addr.s_addr, | ||||||
|  |  				   0, 0, | ||||||
|  | -				   IPPROTO_GRE, RT_CONN_FLAGS(sk), | ||||||
|  | -				   sk->sk_bound_dev_if); | ||||||
|  | +				   IPPROTO_GRE, RT_CONN_FLAGS(sk), 0); | ||||||
|  |  	if (IS_ERR(rt)) { | ||||||
|  |  		error = -EHOSTUNREACH; | ||||||
|  |  		goto end; | ||||||
|  | @@ -464,7 +574,7 @@ static int pptp_connect(struct socket *s | ||||||
|  |   | ||||||
|  |  	opt->dst_addr = sp->sa_addr.pptp; | ||||||
|  |  	sk->sk_state |= PPPOX_CONNECTED; | ||||||
|  | - | ||||||
|  | +	opt->pptp_offload_mode = false; | ||||||
|  |   end: | ||||||
|  |  	release_sock(sk); | ||||||
|  |  	return error; | ||||||
|  | @@ -594,9 +704,169 @@ static int pptp_ppp_ioctl(struct ppp_cha | ||||||
|  |  	return err; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* pptp_channel_addressing_get() | ||||||
|  | + *	Return PPTP channel specific addressing information. | ||||||
|  | + */ | ||||||
|  | +void pptp_channel_addressing_get(struct pptp_opt *opt, struct ppp_channel *chan) | ||||||
|  | +{ | ||||||
|  | +	struct sock *sk; | ||||||
|  | +	struct pppox_sock *po; | ||||||
|  | + | ||||||
|  | +	if (!opt) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	sk = (struct sock *)chan->private; | ||||||
|  | +	if (!sk) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	sock_hold(sk); | ||||||
|  | + | ||||||
|  | +	/* This is very unlikely, but check the socket is connected state */ | ||||||
|  | +	if (unlikely(sock_flag(sk, SOCK_DEAD) || | ||||||
|  | +		     !(sk->sk_state & PPPOX_CONNECTED))) { | ||||||
|  | +		sock_put(sk); | ||||||
|  | +		return; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	po = pppox_sk(sk); | ||||||
|  | +	memcpy(opt, &po->proto.pptp, sizeof(struct pptp_opt)); | ||||||
|  | +	sock_put(sk); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_channel_addressing_get); | ||||||
|  | + | ||||||
|  | +/* pptp_session_find() | ||||||
|  | + *	Search and return a PPTP session info based on peer callid and IP | ||||||
|  | + *	address. The function accepts the parameters in network byte order. | ||||||
|  | + */ | ||||||
|  | +int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, | ||||||
|  | +		      __be32 peer_ip_addr) | ||||||
|  | +{ | ||||||
|  | +	if (!opt) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	return lookup_session_dst(opt, ntohs(peer_call_id), peer_ip_addr); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_session_find); | ||||||
|  | + | ||||||
|  | +/* pptp_session_find_by_src_callid() | ||||||
|  | + *	Search and return a PPTP session info based on src callid and IP | ||||||
|  | + *	address. The function accepts the parameters in network byte order. | ||||||
|  | + */ | ||||||
|  | +int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, | ||||||
|  | +		      __be32 daddr, __be32 saddr) | ||||||
|  | +{ | ||||||
|  | +	if (!opt) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_session_find_by_src_callid); | ||||||
|  | + | ||||||
|  | + /* Function to change the offload mode true/false for a PPTP session */ | ||||||
|  | +static int pptp_set_offload_mode(bool accel_mode, | ||||||
|  | +				 __be16 peer_call_id, __be32 peer_ip_addr) | ||||||
|  | +{ | ||||||
|  | +	struct pppox_sock *sock; | ||||||
|  | +	int i = 1; | ||||||
|  | + | ||||||
|  | +	rcu_read_lock(); | ||||||
|  | +	for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { | ||||||
|  | +		sock = rcu_dereference(callid_sock[i]); | ||||||
|  | +		if (!sock) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		if (sock->proto.pptp.dst_addr.call_id == peer_call_id && | ||||||
|  | +		    sock->proto.pptp.dst_addr.sin_addr.s_addr == peer_ip_addr) { | ||||||
|  | +			sock_hold(sk_pppox(sock)); | ||||||
|  | +			sock->proto.pptp.pptp_offload_mode = accel_mode; | ||||||
|  | +			sock_put(sk_pppox(sock)); | ||||||
|  | +			rcu_read_unlock(); | ||||||
|  | +			return 0; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	rcu_read_unlock(); | ||||||
|  | +	return -EINVAL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* Enable the PPTP session offload flag */ | ||||||
|  | +int pptp_session_enable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) | ||||||
|  | +{ | ||||||
|  | +	return pptp_set_offload_mode(true, peer_call_id, peer_ip_addr); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_session_enable_offload_mode); | ||||||
|  | + | ||||||
|  | +/* Disable the PPTP session offload flag */ | ||||||
|  | +int pptp_session_disable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) | ||||||
|  | +{ | ||||||
|  | +	return pptp_set_offload_mode(false, peer_call_id, peer_ip_addr); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_session_disable_offload_mode); | ||||||
|  | + | ||||||
|  | +/* Register the offload callback function on behalf of the module which | ||||||
|  | + * will own the sequence and acknowledgment number updates for all | ||||||
|  | + * PPTP GRE packets. All PPTP GRE packets are then transmitted to this | ||||||
|  | + * module after encapsulation in order to ensure the correct seq/ack | ||||||
|  | + * fields are set in the packets before transmission. This is required | ||||||
|  | + * when PPTP flows are offloaded to acceleration engines, in-order to | ||||||
|  | + * ensure consistency in sequence and ack numbers between PPTP control | ||||||
|  | + * (PPP LCP) and data packets | ||||||
|  | + */ | ||||||
|  | +int pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t | ||||||
|  | +					   pptp_gre_offload_cb) | ||||||
|  | +{ | ||||||
|  | +	pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; | ||||||
|  | + | ||||||
|  | +	rcu_read_lock(); | ||||||
|  | +	pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); | ||||||
|  | + | ||||||
|  | +	if (pptp_gre_offload_cb_f) { | ||||||
|  | +		rcu_read_unlock(); | ||||||
|  | +		return -1; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	rcu_assign_pointer(pptp_gre_offload_xmit_cb, pptp_gre_offload_cb); | ||||||
|  | +	rcu_read_unlock(); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_register_gre_seq_offload_callback); | ||||||
|  | + | ||||||
|  | +/* Unregister the PPTP GRE packets sequence number offload callback */ | ||||||
|  | +void pptp_unregister_gre_seq_offload_callback(void) | ||||||
|  | +{ | ||||||
|  | +	rcu_assign_pointer(pptp_gre_offload_xmit_cb, NULL); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(pptp_unregister_gre_seq_offload_callback); | ||||||
|  | + | ||||||
|  | +/* pptp_hold_chan() */ | ||||||
|  | +static void pptp_hold_chan(struct ppp_channel *chan) | ||||||
|  | +{ | ||||||
|  | +	struct sock *sk = (struct sock *)chan->private; | ||||||
|  | + | ||||||
|  | +	sock_hold(sk); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* pptp_release_chan() */ | ||||||
|  | +static void pptp_release_chan(struct ppp_channel *chan) | ||||||
|  | +{ | ||||||
|  | +	struct sock *sk = (struct sock *)chan->private; | ||||||
|  | + | ||||||
|  | +	sock_put(sk); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* pptp_get_channel_protocol() | ||||||
|  | + *     Return the protocol type of the PPTP over PPP protocol | ||||||
|  | + */ | ||||||
|  | +static int pptp_get_channel_protocol(struct ppp_channel *chan) | ||||||
|  | +{ | ||||||
|  | +	return PX_PROTO_PPTP; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static const struct ppp_channel_ops pptp_chan_ops = { | ||||||
|  |  	.start_xmit = pptp_xmit, | ||||||
|  |  	.ioctl      = pptp_ppp_ioctl, | ||||||
|  | +	.get_channel_protocol = pptp_get_channel_protocol, | ||||||
|  | +	.hold = pptp_hold_chan, | ||||||
|  | +	.release = pptp_release_chan, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  static struct proto pptp_sk_proto __read_mostly = { | ||||||
| @@ -0,0 +1,77 @@ | |||||||
|  | --- a/include/net/ip6_tunnel.h | ||||||
|  | +++ b/include/net/ip6_tunnel.h | ||||||
|  | @@ -36,6 +36,7 @@ struct __ip6_tnl_parm { | ||||||
|  |  	__u8 proto;		/* tunnel protocol */ | ||||||
|  |  	__u8 encap_limit;	/* encapsulation limit for tunnel */ | ||||||
|  |  	__u8 hop_limit;		/* hop limit for tunnel */ | ||||||
|  | +	__u8 draft03;		/* FMR using draft03 of map-e - QCA NSS Clients Support */ | ||||||
|  |  	bool collect_md; | ||||||
|  |  	__be32 flowinfo;	/* traffic class and flowlabel for tunnel */ | ||||||
|  |  	__u32 flags;		/* tunnel flags */ | ||||||
|  | --- a/include/net/ip_tunnels.h | ||||||
|  | +++ b/include/net/ip_tunnels.h | ||||||
|  | @@ -531,4 +531,9 @@ static inline void ip_tunnel_info_opts_s | ||||||
|  |   | ||||||
|  |  #endif /* CONFIG_INET */ | ||||||
|  |   | ||||||
|  | +/* QCA NSS Clients Support - Start */ | ||||||
|  | +void ipip6_update_offload_stats(struct net_device *dev, void *ptr); | ||||||
|  | +void ip6_update_offload_stats(struct net_device *dev, void *ptr); | ||||||
|  | +/* QCA NSS Clients Support - End */ | ||||||
|  | + | ||||||
|  |  #endif /* __NET_IP_TUNNELS_H */ | ||||||
|  | --- a/net/ipv6/ip6_tunnel.c | ||||||
|  | +++ b/net/ipv6/ip6_tunnel.c | ||||||
|  | @@ -2429,6 +2429,26 @@ nla_put_failure: | ||||||
|  |  	return -EMSGSIZE; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* QCA NSS Client Support - Start */ | ||||||
|  | +/* | ||||||
|  | + * Update offload stats | ||||||
|  | + */ | ||||||
|  | +void ip6_update_offload_stats(struct net_device *dev, void *ptr) | ||||||
|  | +{ | ||||||
|  | +	struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); | ||||||
|  | +	const struct pcpu_sw_netstats *offload_stats = | ||||||
|  | +					(struct pcpu_sw_netstats *)ptr; | ||||||
|  | + | ||||||
|  | +	u64_stats_update_begin(&tstats->syncp); | ||||||
|  | +	tstats->tx_packets += offload_stats->tx_packets; | ||||||
|  | +	tstats->tx_bytes   += offload_stats->tx_bytes; | ||||||
|  | +	tstats->rx_packets += offload_stats->rx_packets; | ||||||
|  | +	tstats->rx_bytes   += offload_stats->rx_bytes; | ||||||
|  | +	u64_stats_update_end(&tstats->syncp); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(ip6_update_offload_stats); | ||||||
|  | +/* QCA NSS Client Support - End */ | ||||||
|  | + | ||||||
|  |  struct net *ip6_tnl_get_link_net(const struct net_device *dev) | ||||||
|  |  { | ||||||
|  |  	struct ip6_tnl *tunnel = netdev_priv(dev); | ||||||
|  | --- a/net/ipv6/sit.c | ||||||
|  | +++ b/net/ipv6/sit.c | ||||||
|  | @@ -1794,6 +1794,23 @@ nla_put_failure: | ||||||
|  |  	return -EMSGSIZE; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* QCA NSS Clients Support - Start */ | ||||||
|  | +void ipip6_update_offload_stats(struct net_device *dev, void *ptr) | ||||||
|  | +{ | ||||||
|  | +	struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); | ||||||
|  | +	const struct pcpu_sw_netstats *offload_stats = | ||||||
|  | +					(struct pcpu_sw_netstats *)ptr; | ||||||
|  | + | ||||||
|  | +	u64_stats_update_begin(&tstats->syncp); | ||||||
|  | +	tstats->tx_packets += offload_stats->tx_packets; | ||||||
|  | +	tstats->tx_bytes   += offload_stats->tx_bytes; | ||||||
|  | +	tstats->rx_packets += offload_stats->rx_packets; | ||||||
|  | +	tstats->rx_bytes   += offload_stats->rx_bytes; | ||||||
|  | +	u64_stats_update_end(&tstats->syncp); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(ipip6_update_offload_stats); | ||||||
|  | +/* QCA NSS Clients Support - End */ | ||||||
|  | + | ||||||
|  |  static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { | ||||||
|  |  	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 }, | ||||||
|  |  	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 }, | ||||||
| @@ -0,0 +1,119 @@ | |||||||
|  | --- a/drivers/net/vxlan.c | ||||||
|  | +++ b/drivers/net/vxlan.c | ||||||
|  | @@ -90,6 +90,20 @@ struct vxlan_fdb { | ||||||
|  |  /* salt for hash table */ | ||||||
|  |  static u32 vxlan_salt __read_mostly; | ||||||
|  |   | ||||||
|  | +ATOMIC_NOTIFIER_HEAD(vxlan_fdb_notifier_list); | ||||||
|  | + | ||||||
|  | +void vxlan_fdb_register_notify(struct notifier_block *nb) | ||||||
|  | +{ | ||||||
|  | +	atomic_notifier_chain_register(&vxlan_fdb_notifier_list, nb); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(vxlan_fdb_register_notify); | ||||||
|  | + | ||||||
|  | +void vxlan_fdb_unregister_notify(struct notifier_block *nb) | ||||||
|  | +{ | ||||||
|  | +	atomic_notifier_chain_unregister(&vxlan_fdb_notifier_list, nb); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(vxlan_fdb_unregister_notify); | ||||||
|  | + | ||||||
|  |  static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) | ||||||
|  |  { | ||||||
|  |  	return vs->flags & VXLAN_F_COLLECT_METADATA || | ||||||
|  | @@ -367,6 +381,7 @@ static void __vxlan_fdb_notify(struct vx | ||||||
|  |  { | ||||||
|  |  	struct net *net = dev_net(vxlan->dev); | ||||||
|  |  	struct sk_buff *skb; | ||||||
|  | +	struct vxlan_fdb_event vfe; | ||||||
|  |  	int err = -ENOBUFS; | ||||||
|  |   | ||||||
|  |  	skb = nlmsg_new(vxlan_nlmsg_size(), GFP_ATOMIC); | ||||||
|  | @@ -382,6 +397,10 @@ static void __vxlan_fdb_notify(struct vx | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); | ||||||
|  | +	vfe.dev = vxlan->dev; | ||||||
|  | +	vfe.rdst = rd; | ||||||
|  | +	ether_addr_copy(vfe.eth_addr, fdb->eth_addr); | ||||||
|  | +	atomic_notifier_call_chain(&vxlan_fdb_notifier_list, type, (void *)&vfe); | ||||||
|  |  	return; | ||||||
|  |  errout: | ||||||
|  |  	if (err < 0) | ||||||
|  | @@ -548,6 +567,18 @@ static struct vxlan_fdb *vxlan_find_mac( | ||||||
|  |  	return f; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* Find and update age of fdb entry corresponding to MAC. */ | ||||||
|  | +void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni) | ||||||
|  | +{ | ||||||
|  | +	u32 hash_index; | ||||||
|  | + | ||||||
|  | +	hash_index = fdb_head_index(vxlan, mac, vni); | ||||||
|  | +	spin_lock_bh(&vxlan->hash_lock[hash_index]); | ||||||
|  | +	vxlan_find_mac(vxlan, mac, vni); | ||||||
|  | +	spin_unlock_bh(&vxlan->hash_lock[hash_index]); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL(vxlan_fdb_update_mac); | ||||||
|  | + | ||||||
|  |  /* caller should hold vxlan->hash_lock */ | ||||||
|  |  static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f, | ||||||
|  |  					      union vxlan_addr *ip, __be16 port, | ||||||
|  | @@ -2744,6 +2775,9 @@ static void vxlan_xmit_one(struct sk_buf | ||||||
|  |  			goto out_unlock; | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  | +		/* Reset the skb_iif to Tunnels interface index */ | ||||||
|  | +		skb->skb_iif = dev->ifindex; | ||||||
|  | + | ||||||
|  |  		tos = ip_tunnel_ecn_encap(tos, old_iph, skb); | ||||||
|  |  		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); | ||||||
|  |  		err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), | ||||||
|  | @@ -2814,6 +2848,9 @@ static void vxlan_xmit_one(struct sk_buf | ||||||
|  |  		if (err < 0) | ||||||
|  |  			goto tx_error; | ||||||
|  |   | ||||||
|  | +		/* Reset the skb_iif to Tunnels interface index */ | ||||||
|  | +		skb->skb_iif = dev->ifindex; | ||||||
|  | + | ||||||
|  |  		udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev, | ||||||
|  |  				     &local_ip.sin6.sin6_addr, | ||||||
|  |  				     &dst->sin6.sin6_addr, tos, ttl, | ||||||
|  | --- a/include/net/vxlan.h | ||||||
|  | +++ b/include/net/vxlan.h | ||||||
|  | @@ -293,6 +293,19 @@ struct vxlan_dev { | ||||||
|  |  					 VXLAN_F_UDP_ZERO_CSUM6_RX |	\ | ||||||
|  |  					 VXLAN_F_COLLECT_METADATA) | ||||||
|  |   | ||||||
|  | +/* | ||||||
|  | + * Application data for fdb notifier event | ||||||
|  | + */ | ||||||
|  | +struct vxlan_fdb_event { | ||||||
|  | +	struct net_device *dev; | ||||||
|  | +	struct vxlan_rdst *rdst; | ||||||
|  | +	u8 eth_addr[ETH_ALEN]; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +extern void vxlan_fdb_register_notify(struct notifier_block *nb); | ||||||
|  | +extern void vxlan_fdb_unregister_notify(struct notifier_block *nb); | ||||||
|  | +extern void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni); | ||||||
|  | + | ||||||
|  |  struct net_device *vxlan_dev_create(struct net *net, const char *name, | ||||||
|  |  				    u8 name_assign_type, struct vxlan_config *conf); | ||||||
|  |   | ||||||
|  | @@ -376,6 +389,15 @@ static inline __be32 vxlan_compute_rco(u | ||||||
|  |  	return vni_field; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +/* | ||||||
|  | + * vxlan_get_vni() | ||||||
|  | + *	Returns the vni corresponding to tunnel | ||||||
|  | + */ | ||||||
|  | +static inline u32 vxlan_get_vni(struct vxlan_dev *vxlan_tun) | ||||||
|  | +{ | ||||||
|  | +	return be32_to_cpu(vxlan_tun->cfg.vni); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) | ||||||
|  |  { | ||||||
|  |  	return vs->sock->sk->sk_family; | ||||||
		Reference in New Issue
	
	Block a user
	 ACwifidude
					ACwifidude