[PATCH net-next] net: ipv6: support Application-aware IPv6 Network (APN6)
From: Jianwei Mao (Mao) <hidden>
Date: 2020-04-19 03:34:37
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 <redacted> --- 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