[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <71eb2d7b-6afa-48fd-af96-140dd6ddd1e0.mao-linux@maojianwei.com>
Date: Sun, 19 Apr 2020 11:33:44 +0800
From: "Jianwei Mao (Mao)" <mao-linux@...jianwei.com>
To: "netdev" <netdev@...r.kernel.org>
Cc: "davem" <davem@...emloft.net>, "kuznet" <kuznet@....inr.ac.ru>,
"yoshfuji" <yoshfuji@...ux-ipv6.org>, "kuba" <kuba@...nel.org>,
"maojianwei" <maojianwei@...wei.com>
Subject: [PATCH net-next] net: ipv6: support Application-aware IPv6 Network (APN6)
Hi friends,
I would like to propose this new feature for you and linux networking:
support Application-aware IPv6 Network (APN6)
Content of my patch file is as follow. Appreciate your reviews and comments, thanks :)
Feature: support Application-aware IPv6 Network (APN6)
This feature allows application client/server set APN6 infos to sockets
they are using to communicate to each other, by setsockopt().
APN6 infos include three fields now: SLA, AppID and UserID. This APN6
infos will be encapsulated in IPv6 Hop-by-Hop(HBH) extension header,
as an APN6 option TLV.
After that, network can provide specific performance for Apps, such as,
low-latency for online Games, low-jitter for industrial control,
enough-bandwidth for video conference/remote medical system, etc.
This feature is to support APN6 IETF Standard draft:
https://datatracker.ietf.org/doc/draft-li-6man-app-aware-ipv6-network
We made two changes:
1. add IPV6_APN6 as an 'optname' for IPPROTO_IPV6 'level'.
2. add a function to generate IPv6 APN6 HBH header, and re-use
IPV6_HOPOPTS procedure to set this header to socket opt.
Signed-off-by: Jianwei Mao <mao-linux@...jianwei.com>
---
include/uapi/linux/in6.h | 4 ++
net/ipv6/ipv6_sockglue.c | 97 +++++++++++++++++++++++++++++++++-------
2 files changed, 86 insertions(+), 15 deletions(-)
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 9f2273a08356..6601cad58415 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -297,4 +297,8 @@ struct in6_flowlabel_req {
* ...
* MRT6_MAX
*/
+
+/* APN6: Application-aware IPv6 Network */
+#define IPV6_APN6 81
+
#endif /* _UAPI_LINUX_IN6_H */
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index debdaeba5d8c..929cbaf27c27 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -136,6 +136,59 @@ static bool setsockopt_needs_rtnl(int optname)
return false;
}
+#define APN6_HBH_LEN 16
+#define APN6_HBH_HDR_LEN 4
+#define APN6_OPTION_TYPE 0x03
+#define APN6_OPTION_LEN (APN6_HBH_LEN - APN6_HBH_HDR_LEN)
+#define APN6_SLA_SIZE 4
+#define APN6_APPID_SIZE 4
+#define APN6_USERID_SIZE 4
+/* Return APN6 Hop-by-Hop(HBH) extension header */
+static void *generate_apn6_hopopts(char __user *optval, unsigned int optlen)
+{
+ unsigned char *hbh;
+ unsigned int sla, app_id, user_id;
+
+ if (optlen < (sizeof(unsigned int) * 3))
+ return NULL;
+ else if (!optval)
+ return NULL;
+
+ if (get_user(sla, ((unsigned int __user *)optval)) ||
+ get_user(app_id, ((unsigned int __user *)optval) + 1) ||
+ get_user(user_id, ((unsigned int __user *)optval) + 2))
+ return ERR_PTR(-EFAULT);
+
+ pr_info("APN6: Get info: SLA:%08X AppID:%08X UserID:%08X",
+ sla, app_id, user_id);
+
+ hbh = kzalloc(APN6_HBH_LEN, GFP_KERNEL);
+ // hbh[0] is 0x0 now, and will be set natively when sending packets.
+ hbh[1] = (APN6_HBH_LEN >> 3) - 1;
+ hbh[2] = APN6_OPTION_TYPE;
+ hbh[3] = APN6_OPTION_LEN;
+
+ sla = htonl(sla);
+ app_id = htonl(app_id);
+ user_id = htonl(user_id);
+ memcpy(hbh + APN6_HBH_HDR_LEN, &sla, APN6_SLA_SIZE);
+ memcpy(hbh + APN6_HBH_HDR_LEN + APN6_SLA_SIZE, &app_id, APN6_APPID_SIZE);
+ memcpy(hbh + APN6_HBH_HDR_LEN + APN6_SLA_SIZE + APN6_APPID_SIZE,
+ &user_id, APN6_USERID_SIZE);
+
+ pr_info("APN6: Generate APN6 Hop-by-Hop extension header:\n"
+ "%02X %02X %02X %02X\n"
+ "%02X %02X %02X %02X\n"
+ "%02X %02X %02X %02X\n"
+ "%02X %02X %02X %02X",
+ hbh[0], hbh[1], hbh[2], hbh[3],
+ hbh[4], hbh[5], hbh[6], hbh[7],
+ hbh[8], hbh[9], hbh[10], hbh[11],
+ hbh[12], hbh[13], hbh[14], hbh[15]);
+
+ return hbh;
+}
+
static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
{
@@ -400,34 +453,48 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_RTHDRDSTOPTS:
case IPV6_RTHDR:
case IPV6_DSTOPTS:
+ case IPV6_APN6:
{
struct ipv6_txoptions *opt;
struct ipv6_opt_hdr *new = NULL;
/* hop-by-hop / destination options are privileged option */
retv = -EPERM;
- if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
+ if (optname != IPV6_APN6 && optname != IPV6_RTHDR &&
+ !ns_capable(net->user_ns, CAP_NET_RAW))
break;
- /* remove any sticky options header with a zero option
- * length, per RFC3542.
- */
- if (optlen == 0)
- optval = NULL;
- else if (!optval)
- goto e_inval;
- else if (optlen < sizeof(struct ipv6_opt_hdr) ||
- optlen & 0x7 || optlen > 8 * 255)
- goto e_inval;
- else {
- new = memdup_user(optval, optlen);
+ if (optname == IPV6_APN6) {
+ new = generate_apn6_hopopts(optval, optlen);
if (IS_ERR(new)) {
retv = PTR_ERR(new);
+ pr_warn("APN6: Fail when generate HBH, %d", retv);
break;
}
- if (unlikely(ipv6_optlen(new) > optlen)) {
- kfree(new);
+ // next steps are same as IPV6_HOPOPTS procedure,
+ // so we can reuse it.
+ optname = IPV6_HOPOPTS;
+ } else {
+ /* remove any sticky options header with a zero option
+ * length, per RFC3542.
+ */
+ if (optlen == 0)
+ optval = NULL;
+ else if (!optval)
+ goto e_inval;
+ else if (optlen < sizeof(struct ipv6_opt_hdr) ||
+ optlen & 0x7 || optlen > 8 * 255)
goto e_inval;
+ else {
+ new = memdup_user(optval, optlen);
+ if (IS_ERR(new)) {
+ retv = PTR_ERR(new);
+ break;
+ }
+ if (unlikely(ipv6_optlen(new) > optlen)) {
+ kfree(new);
+ goto e_inval;
+ }
}
}
--
2.17.1
Powered by blists - more mailing lists