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