[qca-nss-sfe] Add Tx support for PPPoE
Change-Id: Iae53d1eb116ff847457c2da2864ecd21ad8ae0be
Signed-off-by: Guduri Prathyusha <quic_gprathyu@quicinc.com>
diff --git a/Makefile b/Makefile
index a685a65..fb015f7 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@
SFE_BASE_OBJS := sfe.o sfe_init.o
SFE_IPV4_OBJS := sfe_ipv4.o sfe_ipv4_udp.o sfe_ipv4_tcp.o sfe_ipv4_icmp.o
SFE_IPV6_OBJS := sfe_ipv6.o sfe_ipv6_udp.o sfe_ipv6_tcp.o sfe_ipv6_icmp.o
+SFE_PPPOE_OBJS := sfe_pppoe.o
obj-m += qca-nss-sfe.o
@@ -17,6 +18,7 @@
# IPv4 files
#
qca-nss-sfe-objs += $(SFE_IPV4_OBJS)
+qca-nss-sfe-objs += $(SFE_PPPOE_OBJS)
ifdef SFE_SUPPORT_IPV6
qca-nss-sfe-objs += $(SFE_IPV6_OBJS)
diff --git a/sfe_ipv4.c b/sfe_ipv4.c
index 868e996..f2fd60e 100644
--- a/sfe_ipv4.c
+++ b/sfe_ipv4.c
@@ -919,6 +919,26 @@
}
/*
+ * sfe_ipv4_xmit_eth_type_check()
+ * Checking if MAC header has to be written.
+ */
+static inline bool sfe_ipv4_xmit_eth_type_check(struct net_device *dev, u32 cm_flags)
+{
+ if (!(dev->flags & IFF_NOARP)) {
+ return true;
+ }
+
+ /*
+ * For PPPoE, since we are now supporting PPPoE encapsulation, we are writing L2 header.
+ */
+ if (unlikely(cm_flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
* sfe_ipv4_create_rule()
* Create a forwarding rule.
*/
@@ -1141,7 +1161,7 @@
/*
* For the non-arp interface, we don't write L2 HDR.
*/
- if (!(dest_dev->flags & IFF_NOARP)) {
+ if (sfe_ipv4_xmit_eth_type_check(dest_dev, original_cm->flags)) {
/*
* Check whether the rule has configured a specific source MAC address to use.
@@ -1230,7 +1250,7 @@
/*
* For the non-arp interface, we don't write L2 HDR.
*/
- if (!(src_dev->flags & IFF_NOARP)) {
+ if (sfe_ipv4_xmit_eth_type_check(src_dev, reply_cm->flags)) {
/*
* Check whether the rule has configured a specific source MAC address to use.
@@ -1713,7 +1733,7 @@
last_sync_jiffies, mark);
if (original_cm_flags &= (SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_DECAP | SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP)) {
- bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "pppoe session_id=\"%u\" pppoe server MAC=\"%pM\" ",
+ bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "pppoe_session_id=\"%u\" pppoe_server MAC=\"%pM\" ",
pppoe_session_id, pppoe_remote_mac);
}
diff --git a/sfe_ipv4.h b/sfe_ipv4.h
index 2496327..75b89d5 100644
--- a/sfe_ipv4.h
+++ b/sfe_ipv4.h
@@ -233,6 +233,7 @@
SFE_IPV4_EXCEPTION_EVENT_DATAGRAM_INCOMPLETE,
SFE_IPV4_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE,
SFE_IPV4_EXCEPTION_EVENT_UNHANDLED_PROTOCOL,
+ SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED,
SFE_IPV4_EXCEPTION_EVENT_LAST
};
@@ -262,6 +263,7 @@
u64 packets_forwarded64; /* Number of IPv4 packets forwarded */
u64 packets_not_forwarded64; /* Number of IPv4 packets not forwarded */
u64 exception_events64[SFE_IPV4_EXCEPTION_EVENT_LAST];
+ u64 pppoe_encap_packets_forwarded64; /* Number of IPv4 PPPOE encap packets forwarded */
};
/*
diff --git a/sfe_ipv4_tcp.c b/sfe_ipv4_tcp.c
index b9dcdce..4450184 100644
--- a/sfe_ipv4_tcp.c
+++ b/sfe_ipv4_tcp.c
@@ -28,6 +28,7 @@
#include "sfe.h"
#include "sfe_flow_cookie.h"
#include "sfe_ipv4.h"
+#include "sfe_pppoe.h"
/*
* sfe_ipv4_process_tcp_option_sack()
@@ -485,6 +486,23 @@
}
/*
+ * For PPPoE flows, add PPPoE header before L2 header is added.
+ */
+ if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
+ if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IP))) {
+ rcu_read_unlock();
+ DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
+ sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+ return 0;
+ }
+ this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
+ }
+
+ /*
+ * TODO : VLAN headers if any should be added here when supported.
+ */
+
+ /*
* Update DSCP
*/
if (unlikely(cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
diff --git a/sfe_ipv4_udp.c b/sfe_ipv4_udp.c
index 1d1a4df..28c7a43 100644
--- a/sfe_ipv4_udp.c
+++ b/sfe_ipv4_udp.c
@@ -28,6 +28,7 @@
#include "sfe.h"
#include "sfe_flow_cookie.h"
#include "sfe_ipv4.h"
+#include "sfe_pppoe.h"
/*
* sfe_ipv4_recv_udp()
@@ -198,6 +199,23 @@
iph->ttl = ttl - 1;
/*
+ * For PPPoE flows, add PPPoE header before L2 header is added.
+ */
+ if (cm->flags & SFE_IPV4_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
+ if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IP))) {
+ rcu_read_unlock();
+ DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
+ sfe_ipv4_exception_stats_inc(si, SFE_IPV4_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+ return 0;
+ }
+ this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
+ }
+
+ /*
+ * TODO: VLAN header should be added here when they are supported.
+ */
+
+ /*
* Enable HW csum if rx checksum is verified and xmit interface is CSUM offload capable.
* Note: If L4 csum at Rx was found to be incorrect, we (router) should use incremental L4 checksum here
* so that HW does not re-calculate/replace the L4 csum
diff --git a/sfe_ipv6.c b/sfe_ipv6.c
index ad39f1e..5d2c32c 100644
--- a/sfe_ipv6.c
+++ b/sfe_ipv6.c
@@ -909,6 +909,26 @@
}
/*
+ * sfe_ipv6_xmit_eth_type_check
+ * Checking if MAC header has to be written.
+ */
+static inline bool sfe_ipv6_xmit_eth_type_check(struct net_device *dev, u32 cm_flags)
+{
+ if (!(dev->flags & IFF_NOARP)) {
+ return true;
+ }
+
+ /*
+ * For PPPoE, since we are now supporting PPPoE encapsulation, we are writing L2 header.
+ */
+ if (cm_flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
* sfe_ipv6_create_rule()
* Create a forwarding rule.
*/
@@ -1090,8 +1110,9 @@
/*
* For the non-arp interface, we don't write L2 HDR.
+ * Excluding PPPoE from this, since we are now supporting PPPoE encap/decap.
*/
- if (!(dest_dev->flags & IFF_NOARP)) {
+ if (sfe_ipv6_xmit_eth_type_check(dest_dev, original_cm->flags)) {
/*
* Check whether the rule has configured a specific source MAC address to use.
@@ -1208,8 +1229,9 @@
/*
* For the non-arp interface, we don't write L2 HDR.
+ * Excluding PPPoE from this, since we are now supporting PPPoE encap/decap.
*/
- if (!(src_dev->flags & IFF_NOARP)) {
+ if (sfe_ipv6_xmit_eth_type_check(src_dev, reply_cm->flags)) {
/*
* Check whether the rule has configured a specific source MAC address to use.
@@ -1678,7 +1700,7 @@
last_sync_jiffies, mark);
if (original_cm_flags &= (SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_DECAP | SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP)) {
- bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "pppoe session_id=\"%u\" pppoe server MAC=\"%pM\" ",
+ bytes_read += snprintf(msg + bytes_read, CHAR_DEV_MSG_SIZE, "pppoe_session_id=\"%u\" pppoe_server_MAC=\"%pM\" ",
pppoe_session_id, pppoe_remote_mac);
}
diff --git a/sfe_ipv6.h b/sfe_ipv6.h
index 1bb773a..5e11cc7 100644
--- a/sfe_ipv6.h
+++ b/sfe_ipv6.h
@@ -240,6 +240,7 @@
SFE_IPV6_EXCEPTION_EVENT_IP_OPTIONS_INCOMPLETE,
SFE_IPV6_EXCEPTION_EVENT_UNHANDLED_PROTOCOL,
SFE_IPV6_EXCEPTION_EVENT_FLOW_COOKIE_ADD_FAIL,
+ SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED,
SFE_IPV6_EXCEPTION_EVENT_LAST
};
@@ -270,6 +271,7 @@
u64 packets_forwarded64; /* Number of IPv6 packets forwarded */
u64 packets_not_forwarded64; /* Number of IPv6 packets not forwarded */
u64 exception_events64[SFE_IPV6_EXCEPTION_EVENT_LAST];
+ u64 pppoe_encap_packets_forwarded64; /* Number of IPv6 PPPOE encap packets forwarded */
};
/*
diff --git a/sfe_ipv6_tcp.c b/sfe_ipv6_tcp.c
index 04870e9..e0d362c 100644
--- a/sfe_ipv6_tcp.c
+++ b/sfe_ipv6_tcp.c
@@ -28,6 +28,7 @@
#include "sfe.h"
#include "sfe_flow_cookie.h"
#include "sfe_ipv6.h"
+#include "sfe_pppoe.h"
/*
* sfe_ipv6_process_tcp_option_sack()
@@ -493,6 +494,23 @@
}
/*
+ * For PPPoE flows, add PPPoE header before L2 header is added.
+ */
+ if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
+ if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IPV6))) {
+ rcu_read_unlock();
+ DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
+ sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+ return 0;
+ }
+ this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
+ }
+
+ /*
+ * TODO: VLAN header should be added here when they are supported.
+ */
+
+ /*
* Update DSCP
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
diff --git a/sfe_ipv6_udp.c b/sfe_ipv6_udp.c
index 2523255..2fc79dc 100644
--- a/sfe_ipv6_udp.c
+++ b/sfe_ipv6_udp.c
@@ -28,6 +28,7 @@
#include "sfe.h"
#include "sfe_flow_cookie.h"
#include "sfe_ipv6.h"
+#include "sfe_pppoe.h"
/*
* sfe_ipv6_recv_udp()
@@ -187,6 +188,23 @@
}
/*
+ * For PPPoE flows, add PPPoE header before L2 header is added.
+ */
+ if (cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_PPPOE_ENCAP) {
+ if (unlikely(!sfe_pppoe_add_header(skb, cm->pppoe_session_id, PPP_IPV6))) {
+ rcu_read_unlock();
+ DEBUG_WARN("%px: PPPoE header addition failed\n", skb);
+ sfe_ipv6_exception_stats_inc(si, SFE_IPV6_EXCEPTION_EVENT_PPPOE_HEADER_ENCAP_FAILED);
+ return 0;
+ }
+ this_cpu_inc(si->stats_pcpu->pppoe_encap_packets_forwarded64);
+ }
+
+ /*
+ * TODO: VLAN header should be added here when they are supported.
+ */
+
+ /*
* Update DSCP
*/
if (unlikely(cm->flags & SFE_IPV6_CONNECTION_MATCH_FLAG_DSCP_REMARK)) {
diff --git a/sfe_pppoe.c b/sfe_pppoe.c
new file mode 100644
index 0000000..4b74185
--- /dev/null
+++ b/sfe_pppoe.c
@@ -0,0 +1,82 @@
+/*
+ * sfe_pppoe.c
+ * API for shortcut forwarding engine PPPoE flows
+ *
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/if_pppox.h>
+#include <linux/ppp_defs.h>
+
+#include "sfe_debug.h"
+#include "sfe_api.h"
+#include "sfe.h"
+#include "sfe_pppoe.h"
+
+#define SFE_PPPOE_HEADER_SIZE (sizeof(struct pppoe_hdr) + 2)
+
+/*
+ * sfe_pppoe_add_header()
+ * Add PPPoE header.
+ *
+ * skb->data will point to PPPoE header after the function
+ */
+int sfe_pppoe_add_header(struct sk_buff *skb, u16 pppoe_session_id, u16 ppp_protocol)
+{
+ u16 *l2_header;
+ struct pppoe_hdr *ph;
+ u16 *l3_header = (u16 *)skb->data;
+
+ /*
+ * Check that we have space for PPPoE header and PPP header (2 bytes)
+ */
+ if (unlikely(!pskb_may_pull(skb, SFE_PPPOE_HEADER_SIZE))) {
+ DEBUG_TRACE("%px: Not enough headroom for PPPoE header \n", skb);
+ return 0;
+ }
+
+ /*
+ * PPPoE header (8 bytes) + PPP header (2 bytes)
+ *
+ * Hence move by 10 bytes to accomodate PPPoE header
+ */
+ l2_header = l3_header - (SFE_PPPOE_HEADER_SIZE / 2);
+
+ /*
+ * Headers in skb will look like in below sequence
+ * | PPPoE hdr(10 bytes) | L3 hdr |
+ */
+ ph = (struct pppoe_hdr *)l2_header;
+ ph->ver = 1;
+ ph->type = 1;
+ ph->code = 0;
+ ph->sid = pppoe_session_id;
+ ph->length = skb->len;
+ skb->protocol = cpu_to_be16(ETH_P_PPP_SES);
+
+ /*
+ * Insert the PPP header protocol
+ */
+ *(l2_header + 4) = ppp_protocol;
+
+ /*
+ * L2 header offset will point to PPPoE header,
+ * since sfe_ipv4_recv_tcp/udp() does skb_push by ETH_HLEN before adding L2 header.
+ */
+ __skb_push(skb, SFE_PPPOE_HEADER_SIZE);
+
+ return 1;
+}
diff --git a/sfe_pppoe.h b/sfe_pppoe.h
new file mode 100644
index 0000000..6a64bdf
--- /dev/null
+++ b/sfe_pppoe.h
@@ -0,0 +1,21 @@
+/*
+ * sfe_pppoe.h
+ * Shortcut flow acceleration for PPPoE flow
+ *
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/ppp_defs.h>
+
+int sfe_pppoe_add_header(struct sk_buff *skb, u16 pppoe_session_id, u16 ppp_protocol);