TCP_option_address/0005-support-ipv6-from-iqiyi.patch
2022-11-02 16:43:57 +08:00

1971 lines
58 KiB
Diff

From 5b8e37bcab0fc88a4d2f1e5e88def7fd1ee0721f Mon Sep 17 00:00:00 2001
From: sunsuwan <sunsuwan3@huawei.com>
Date: Mon, 31 Oct 2022 19:34:21 +0800
Subject: [PATCH] support ipv6 from iqiyi
Upstream: https://github.com/iqiyi/dpvs/tree/master/kmod/toa
---
src/Makefile | 7 +
src/toa.c | 1595 +++++++++++++++++++++++++++++++++-----------------
src/toa.h | 139 +++--
3 files changed, 1166 insertions(+), 575 deletions(-)
diff --git a/src/Makefile b/src/Makefile
index 277090d..a9e1079 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,6 +4,13 @@
obj-$(CONFIG_TOA) += toa.o
+ccflags-y += -DTOA_IPV6_ENABLE
+ccflags-y += -DTOA_NAT64_ENABLE
+
+ifeq ($(DEBUG), 1)
+ccflags-y += -g -O0
+endif
+
kerver=$(shell rpm -q kernel-devel --queryformat=%{VERSION}-%{RELEASE}.%{ARCH})
default:
diff --git a/src/toa.c b/src/toa.c
index 487ace3..931607d 100644
--- a/src/toa.c
+++ b/src/toa.c
@@ -1,133 +1,402 @@
-#include <linux/kprobes.h>
+/*
+ * DPVS is a software load balancer (Virtual Server) based on DPDK.
+ *
+ * Copyright (C) 2021 iQIYI (www.iqiyi.com).
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
#include "toa.h"
-
/*
- * TOA: Address is a new TCP Option
- * Address include ip+port, Now only support IPV4
+ * TOA: Address is a new TCP Option
+ * Address include ip+port, Now support IPV4 and IPV6
*/
+#if defined(CONFIG_ARM64)
+/*
+ * ARM64 interface
+ * Lookup the page table entry for a virtual address. Return a pointer
+ * to the entry and the level of the mapping.
+ *
+ * Note: We return pud and pmd either when the entry is marked large
+ * or when the present bit is not set. Otherwise we would return a
+ * pointer to a nonexisting mapping.
+ */
+static pte_t *lookup_address(unsigned long address, unsigned int *level)
+{
+ pgd_t *pgdp;
+ pud_t *pudp, pud;
+ pmd_t *pmdp, pmd;
+ pte_t *ptep;
+ unsigned long addr = address;
+
+ unsigned long init_mm = kallsyms_lookup_name("init_mm");
+ if (!init_mm) {
+ TOA_INFO("CPU [%u] lookup_address init_mm null\n", smp_processor_id());
+ return NULL;
+ }
+
+ /*pgdp = pgd_offset_k(addr);*/
+ pgdp = pgd_offset((struct mm_struct *)init_mm, addr);
+ if (pgd_none(READ_ONCE(*pgdp)))
+ return NULL;
+
+ pudp = pud_offset(pgdp, addr);
+ pud = READ_ONCE(*pudp);
+ if (pud_none(pud))
+ return NULL;
+
+ pmdp = pmd_offset(pudp, addr);
+ pmd = READ_ONCE(*pmdp);
+ if (pmd_none(pmd))
+ return NULL;
+
+ ptep = pte_offset_kernel(pmdp, addr);
+ return ptep;
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+#include <linux/kprobes.h>
+static struct kprobe kp = {
+ .symbol_name = "kallsyms_lookup_name"
+};
+
+typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
+#endif
+
unsigned long sk_data_ready_addr = 0;
-typedef unsigned long (*kallsyms_lookup_name_fun_t)(const char *name);
-static kallsyms_lookup_name_fun_t kallsyms_lookup_name_fun;
+#define TOA_NIPQUAD_FMT "%u.%u.%u.%u"
+
+#define TOA_NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+#define TOA_NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+
+#define TOA_NIP6(addr) \
+ ntohs((addr).s6_addr16[0]), \
+ ntohs((addr).s6_addr16[1]), \
+ ntohs((addr).s6_addr16[2]), \
+ ntohs((addr).s6_addr16[3]), \
+ ntohs((addr).s6_addr16[4]), \
+ ntohs((addr).s6_addr16[5]), \
+ ntohs((addr).s6_addr16[6]), \
+ ntohs((addr).s6_addr16[7])
+
+/* ipv6's toa list table array */
+#define TOA_IP6_TAB_BITS 12
+#define TOA_IP6_TAB_SIZE (1 << TOA_IP6_TAB_BITS)
+#define TOA_IP6_TAB_MASK (TOA_IP6_TAB_SIZE - 1)
+
+struct toa_ip6_entry {
+ struct toa_ip6_data toa_data;
+ struct sock *sk;
+
+ struct list_head list;
+};
+
+struct toa_ip6_list_head {
+ struct list_head toa_ip6_head;
+ spinlock_t lock;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+static struct toa_ip6_list_head
+__toa_ip6_list_tab[TOA_IP6_TAB_SIZE] __cacheline_aligned;
+
+/* per-cpu lock for toa of ipv6 */
+struct toa_ip6_sk_lock {
+ /* lock for sk of ip6 toa */
+ spinlock_t __percpu *lock;
+};
+
+static struct toa_ip6_sk_lock toa_ip6_sk_lock;
+#endif
+
+#ifdef TOA_IPV6_ENABLE
+static struct proto_ops *inet6_stream_ops_p = NULL;
+static struct inet_connection_sock_af_ops *ipv6_specific_p = NULL;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1)
+typedef struct sock *(*syn_recv_sock_func_pt)(
+ const struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst,
+ struct request_sock *req_unhash,
+ bool *own_req);
+#else
+typedef struct sock *(*syn_recv_sock_func_pt)(
+ struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst);
+#endif
+static syn_recv_sock_func_pt tcp_v6_syn_recv_sock_org_pt = NULL;
+#endif
/*
* Statistics of toa in proc /proc/net/toa_stats
*/
-
struct toa_stats_entry toa_stats[] = {
- TOA_STAT_ITEM("syn_recv_sock_toa", SYN_RECV_SOCK_TOA_CNT),
- TOA_STAT_ITEM("syn_recv_sock_no_toa", SYN_RECV_SOCK_NO_TOA_CNT),
- TOA_STAT_ITEM("getname_toa_ok", GETNAME_TOA_OK_CNT),
- TOA_STAT_ITEM("getname_toa_mismatch", GETNAME_TOA_MISMATCH_CNT),
- TOA_STAT_ITEM("getname_toa_bypass", GETNAME_TOA_BYPASS_CNT),
- TOA_STAT_ITEM("getname_toa_empty", GETNAME_TOA_EMPTY_CNT),
- TOA_STAT_END
+ TOA_STAT_ITEM("syn_recv_sock_toa", SYN_RECV_SOCK_TOA_CNT),
+ TOA_STAT_ITEM("syn_recv_sock_no_toa", SYN_RECV_SOCK_NO_TOA_CNT),
+ TOA_STAT_ITEM("getname_toa_ok", GETNAME_TOA_OK_CNT),
+ TOA_STAT_ITEM("getname_toa_mismatch", GETNAME_TOA_MISMATCH_CNT),
+ TOA_STAT_ITEM("getname_toa_bypass", GETNAME_TOA_BYPASS_CNT),
+ TOA_STAT_ITEM("getname_toa_empty", GETNAME_TOA_EMPTY_CNT),
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+ TOA_STAT_ITEM("ip6_address_alloc", IP6_ADDR_ALLOC_CNT),
+ TOA_STAT_ITEM("ip6_address_free", IP6_ADDR_FREE_CNT),
+#endif
+ TOA_STAT_END
};
-struct toa_stat_mib *ext_stats;
+unsigned int is_ro_addr(unsigned long addr)
+{
+ unsigned int level;
+ unsigned int ro_enable = 1;
+ pte_t *pte = lookup_address(addr, &level);
+#if defined(CONFIG_ARM64)
+ if (pte_write(*pte)) {
+ ro_enable = 0;
+ }
+#else
+ if (pte->pte & _PAGE_RW) {
+ ro_enable = 0;
+ }
+#endif
+
+ return ro_enable;
+}
-static int toa_get_kallsyms_lookup_name_addr(void)
+void set_addr_rw(unsigned long addr)
{
- static struct kprobe kp = {
- .symbol_name = "kallsyms_lookup_name",
- };
+ unsigned int level;
+ pte_t *pte = lookup_address(addr, &level);
- if (register_kprobe(&kp) < 0)
- return -1;
+#if defined(CONFIG_ARM64)
+ *pte = pte_mkwrite(*pte);
+ __sync_icache_dcache(*pte);
+ flush_tlb_all();
+#else
+ pte->pte |= _PAGE_RW;
+#endif
+ smp_wmb();
+}
- if (!kallsyms_lookup_name_fun) {
- kallsyms_lookup_name_fun = (kallsyms_lookup_name_fun_t)kp.addr;
- }
- unregister_kprobe(&kp);
+void set_addr_ro(unsigned long addr)
+{
+ unsigned int level;
+ pte_t *pte = lookup_address(addr, &level);
- return 0;
+#if defined(CONFIG_ARM64)
+ *pte = pte_wrprotect(*pte);
+ __sync_icache_dcache(*pte);
+ flush_tlb_all();
+#else
+ pte->pte &= ~_PAGE_RW;
+#endif
}
-#if defined(CONFIG_ARM64)
-static pmd_t *toa_get_pmd(unsigned long address)
+DEFINE_TOA_STAT(struct toa_stat_mib, ext_stats);
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,103)
+/* more secured version of ipv6_addr_hash() */
+static inline u32
+__ipv6_addr_jhash(const struct in6_addr *a, const u32 initval)
{
- pgd_t *pgdp;
- pud_t *pudp, pud;
- pmd_t *pmdp;
- unsigned long addr = address;
-
- unsigned long init_mm = kallsyms_lookup_name_fun("init_mm");
- if (!init_mm) {
- TOA_INFO("CPU [%u] lookup_address init_mm null\n", smp_processor_id());
- return NULL;
- }
-
- /*pgdp = pgd_offset_k(addr);*/
- pgdp = pgd_offset((struct mm_struct *)init_mm, addr);
- if (pgd_none(READ_ONCE(*pgdp)))
- return NULL;
-
- pudp = pud_offset((p4d_t *)pgdp, addr);
- pud = READ_ONCE(*pudp);
- if (pud_none(pud))
- return NULL;
-
- pmdp = pmd_offset(pudp, addr);
-
- return pmdp;
+ u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1];
+
+ return jhash_3words(v,
+ (__force u32)a->s6_addr32[2],
+ (__force u32)a->s6_addr32[3],
+ initval);
+}
+#endif
+
+static void
+toa_ip6_hash(struct toa_ip6_entry *ptr_ip6_entry)
+{
+ struct toa_ip6_data *ptr_toa_data = &ptr_ip6_entry->toa_data;
+ __u32 hash_key =
+ __ipv6_addr_jhash(&ptr_toa_data->in6_addr, ptr_toa_data->port) & TOA_IP6_TAB_MASK;
+
+ spin_lock_bh(&__toa_ip6_list_tab[hash_key].lock);
+
+ list_add(&ptr_ip6_entry->list, &__toa_ip6_list_tab[hash_key].toa_ip6_head);
+
+ spin_unlock_bh(&__toa_ip6_list_tab[hash_key].lock);
+
+ return;
}
-static int toa_mkwrite(unsigned long vma)
+static void
+toa_ip6_unhash(struct toa_ip6_entry *ptr_ip6_entry)
{
- pmd_t *pmdp, pmd;
- pte_t *ptep, pte;
-
- pmdp = toa_get_pmd(vma);
- if (NULL == pmdp)
- return 1;
-
- pmd = READ_ONCE(*pmdp);
- if (pmd_none(pmd))
- return 1;
-
- if (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) {
- set_pmd(pmdp, __pmd(pmd_val(pmd) & ~PMD_SECT_RDONLY));
- } else {
- ptep = pte_offset_kernel(pmdp, vma);
- pte = READ_ONCE(*ptep);
- if (pte_none(pte)) {
- return 1;
- }
- set_pte(ptep, pte_mkwrite(pte));
- }
-
- return 0;
+ struct toa_ip6_data *ptr_toa_data = &ptr_ip6_entry->toa_data;
+ __u32 hash_key =
+ __ipv6_addr_jhash(&ptr_toa_data->in6_addr, ptr_toa_data->port) & TOA_IP6_TAB_MASK;
+
+ spin_lock_bh(&__toa_ip6_list_tab[hash_key].lock);
+
+ list_del(&ptr_ip6_entry->list);
+
+ spin_unlock_bh(&__toa_ip6_list_tab[hash_key].lock);
}
-static void toa_wrprotect(unsigned long vma)
+static void
+lock_all_toa_ip6_sk(void)
{
- pmd_t *pmdp, pmd;
- pte_t *ptep, pte;
-
- pmdp = toa_get_pmd(vma);
- if (NULL == pmdp)
- return;
-
- pmd = READ_ONCE(*pmdp);
- if (pmd_none(pmd))
- return;
-
- if (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) {
- set_pmd(pmdp, __pmd(pmd_val(pmd) | PMD_SECT_RDONLY));
- } else {
- ptep = pte_offset_kernel(pmdp, vma);
- pte = READ_ONCE(*ptep);
- if (pte_none(pte)) {
- return;
- }
- set_pte(ptep, pte_wrprotect(pte));
- }
-
- return;
+ int i;
+ for_each_possible_cpu(i) {
+ spinlock_t *lock;
+
+ lock = per_cpu_ptr(toa_ip6_sk_lock.lock, i);
+ spin_lock_bh(lock);
+ }
}
+
+static void
+unlock_all_toa_ip6_sk(void)
+{
+ int i;
+ for_each_possible_cpu(i) {
+ spinlock_t *lock;
+
+ lock = per_cpu_ptr(toa_ip6_sk_lock.lock, i);
+ spin_unlock_bh(lock);
+ }
+}
+
+static void
+lock_cpu_toa_ip6_sk(void)
+{
+ spinlock_t *lock = this_cpu_ptr(toa_ip6_sk_lock.lock);
+ spin_lock_bh(lock);
+}
+
+static void
+unlock_cpu_toa_ip6_sk(void)
+{
+ spinlock_t *lock = this_cpu_ptr(toa_ip6_sk_lock.lock);
+ spin_unlock_bh(lock);
+}
+
+static int
+init_toa_ip6(void)
+{
+ int i;
+
+ toa_ip6_sk_lock.lock = alloc_percpu(spinlock_t);
+ if (toa_ip6_sk_lock.lock == NULL) {
+ TOA_INFO("fail to alloc per cpu ip6's destruct lock\n");
+ return -ENOMEM;
+ }
+
+ for_each_possible_cpu(i) {
+ spinlock_t *lock;
+
+ lock = per_cpu_ptr(toa_ip6_sk_lock.lock, i);
+ spin_lock_init(lock);
+ }
+
+ for (i = 0; i < TOA_IP6_TAB_SIZE; ++i) {
+ INIT_LIST_HEAD(&__toa_ip6_list_tab[i].toa_ip6_head);
+ spin_lock_init(&__toa_ip6_list_tab[i].lock);
+ }
+
+ return 0;
+}
+
+static void
+tcp_v6_sk_destruct_toa(struct sock *sk) {
+
+ lock_cpu_toa_ip6_sk();
+
+ if (sk->sk_user_data) {
+ struct toa_ip6_entry* ptr_ip6_entry = sk->sk_user_data;
+ toa_ip6_unhash(ptr_ip6_entry);
+ sk->sk_destruct = inet_sock_destruct;
+ sk->sk_user_data = NULL;
+ kfree(ptr_ip6_entry);
+ TOA_INC_STATS(ext_stats, IP6_ADDR_FREE_CNT);
+ }
+
+ inet_sock_destruct(sk);
+
+ unlock_cpu_toa_ip6_sk();
+}
+
+static int
+exit_toa_ip6(void)
+{
+ int i;
+ struct list_head *head;
+ struct toa_ip6_entry *ptr_ip6_entry;
+ struct sock *sk;
+
+ lock_all_toa_ip6_sk();
+
+ for (i = 0; i < TOA_IP6_TAB_SIZE; ++i) {
+
+ spin_lock_bh(&__toa_ip6_list_tab[i].lock);
+
+ head = &__toa_ip6_list_tab[i].toa_ip6_head;
+ while (!list_empty(head)) {
+ ptr_ip6_entry = list_first_entry(head, struct toa_ip6_entry, list);
+ sk = ptr_ip6_entry->sk;
+
+ if (sk && sk->sk_user_data &&
+ (sk->sk_destruct == tcp_v6_sk_destruct_toa)) {
+
+ sk->sk_destruct = inet_sock_destruct;
+ sk->sk_user_data = NULL;
+
+ TOA_DBG("free ip6_entry in __toa_ip6_list_tab succ. "
+ "ptr_ip6_entry : %p, toa_ip6 : "TOA_NIP6_FMT", toa_port : %u\n",
+ ptr_ip6_entry,
+ TOA_NIP6(ptr_ip6_entry->toa_data.in6_addr),
+ ptr_ip6_entry->toa_data.port);
+ } else {
+ TOA_DBG("update sk of ip6_entry fail. "
+ "ptr_ip6_entry : %p\n",
+ ptr_ip6_entry);
+ }
+
+ TOA_INC_STATS(ext_stats, IP6_ADDR_FREE_CNT);
+
+ list_del(&ptr_ip6_entry->list);
+ kfree(ptr_ip6_entry);
+ }
+
+ spin_unlock_bh(&__toa_ip6_list_tab[i].lock);
+
+ }
+
+ unlock_all_toa_ip6_sk();
+
+ synchronize_net();
+
+ free_percpu(toa_ip6_sk_lock.lock);
+ return 0;
+}
+
#endif
+
/*
* Funcs for toa hooks
*/
@@ -137,62 +406,112 @@ static void toa_wrprotect(unsigned long vma)
* @return NULL if we don't get client ip/port;
* value of toa_data in ret_ptr if we get client ip/port.
*/
-static void *get_toa_data(struct sk_buff *skb)
+static void *get_toa_data(int af, struct sk_buff *skb, int *nat64)
{
- struct tcphdr *th;
- int length;
- unsigned char *ptr;
-
- struct toa_data tdata;
-
- void *ret_ptr = NULL;
- unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-
- TOA_DBG("get_toa_data called\n");
-
- if (NULL != skb) {
- th = tcp_hdr(skb);
- length = (th->doff * 4) - sizeof(struct tcphdr);
- ptr = skb_header_pointer(skb, sizeof(struct tcphdr),
- length, buff);
- if (!ptr)
- return NULL;
-
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
- switch (opcode) {
- case TCPOPT_EOL:
- return NULL;
- case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
- length--;
- continue;
- default:
- opsize = *ptr++;
- if (opsize < 2) /* "silly options" */
- return NULL;
- if (opsize > length)
- /* don't parse partial options */
- return NULL;
- if (TCPOPT_TOA == opcode &&
- TCPOLEN_TOA == opsize) {
- memcpy(&tdata, ptr - 2, sizeof(tdata));
- TOA_DBG("find toa data: ip = "
- "%u.%u.%u.%u, port = %u\n",
- NIPQUAD(tdata.ip),
- ntohs(tdata.port));
- memcpy(&ret_ptr, &tdata,
- sizeof(ret_ptr));
- TOA_DBG("coded toa data: %p\n",
- ret_ptr);
- return ret_ptr;
- }
- ptr += opsize - 2;
- length -= opsize;
- }
- }
- }
- return NULL;
+ struct tcphdr *th;
+ int length;
+ unsigned char *ptr;
+
+ TOA_DBG("get_toa_data called\n");
+
+ *nat64 = 0;
+ if (NULL != skb) {
+ th = tcp_hdr(skb);
+ length = (th->doff * 4) - sizeof(struct tcphdr);
+ ptr = (unsigned char *) (th + 1);
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize;
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return NULL;
+ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize < 2) /* "silly options" */
+ return NULL;
+ if (opsize > length)
+ /* don't parse partial options */
+ return NULL;
+ if (TCPOPT_TOA == opcode &&
+ TCPOLEN_IP4_TOA == opsize) {
+
+ struct toa_ip4_data tdata;
+ void *ret_ptr = NULL;
+
+ memcpy(&tdata, ptr - 2, sizeof(tdata));
+ TOA_DBG("af = %d, find toa data: ip = "
+ TOA_NIPQUAD_FMT", port = %u\n",
+ af,
+ TOA_NIPQUAD(tdata.ip),
+ ntohs(tdata.port));
+ if (af == AF_INET) {
+ memcpy(&ret_ptr, &tdata,
+ sizeof(ret_ptr));
+ TOA_DBG("coded ip4 toa data: %p\n",
+ ret_ptr);
+ return ret_ptr;
+ }
+#ifdef TOA_IPV6_ENABLE
+ else if (af == AF_INET6) {
+ struct toa_ip6_data *ptr_toa_ip6;
+ struct toa_ip6_entry *ptr_toa_entry =
+ kzalloc(sizeof(struct toa_ip6_entry), GFP_ATOMIC);
+ if (!ptr_toa_entry) {
+ return NULL;
+ }
+
+ ptr_toa_ip6 = &ptr_toa_entry->toa_data;
+ ptr_toa_ip6->opcode = opcode;
+ ptr_toa_ip6->opsize = TCPOLEN_IP6_TOA;
+ ipv6_addr_set(&ptr_toa_ip6->in6_addr, 0, 0,
+ htonl(0x0000FFFF), tdata.ip);
+ ptr_toa_ip6->port = tdata.port;
+ TOA_DBG("coded ip6 toa data: %p\n",
+ ptr_toa_ip6);
+ TOA_INC_STATS(ext_stats, IP6_ADDR_ALLOC_CNT);
+ return ptr_toa_entry;
+ }
+#endif
+ }
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+ if (TCPOPT_TOA == opcode &&
+ TCPOLEN_IP6_TOA == opsize) {
+ struct toa_ip6_data *ptr_toa_ip6;
+ struct toa_ip6_entry *ptr_toa_entry =
+ kzalloc(sizeof(struct toa_ip6_entry), GFP_ATOMIC);
+ if (!ptr_toa_entry) {
+ return NULL;
+ }
+
+ ptr_toa_ip6 = &ptr_toa_entry->toa_data;
+ memcpy(ptr_toa_ip6, ptr - 2, sizeof(struct toa_ip6_data));
+
+ TOA_DBG("find toa_v6 data : ip = "
+ TOA_NIP6_FMT", port = %u,"
+ " coded ip6 toa data: %p\n",
+ TOA_NIP6(ptr_toa_ip6->in6_addr),
+ ptr_toa_ip6->port,
+ ptr_toa_ip6);
+ TOA_INC_STATS(ext_stats, IP6_ADDR_ALLOC_CNT);
+ if (af == AF_INET6)
+ *nat64 = 0;
+ else
+ *nat64 = 1;
+
+ return ptr_toa_entry;
+ }
+#endif
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ }
+ }
+ return NULL;
}
/* get client ip from socket
@@ -203,121 +522,263 @@ static void *get_toa_data(struct sk_buff *skb)
* try to get local address
* @return return what the original inet_getname() returns.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,1)
static int
inet_getname_toa(struct socket *sock, struct sockaddr *uaddr,
- int peer)
+ int peer)
#else
static int
inet_getname_toa(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
+ int *uaddr_len, int peer)
#endif
{
- int retval = 0;
- struct sock *sk = sock->sk;
- struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
- struct toa_data tdata;
+ int retval = 0;
+ struct sock *sk = sock->sk;
+ struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
+ struct toa_ip4_data tdata;
- TOA_DBG("inet_getname_toa called, sk->sk_user_data is %p\n",
- sk->sk_user_data);
+ TOA_DBG("inet_getname_toa called, sk->sk_user_data is %p\n",
+ sk->sk_user_data);
- /* call orginal one */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
- retval = inet_getname(sock, uaddr, peer);
+ /* call orginal one */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,1)
+ retval = inet_getname(sock, uaddr, peer);
#else
- retval = inet_getname(sock, uaddr, uaddr_len, peer);
+ retval = inet_getname(sock, uaddr, uaddr_len, peer);
#endif
- /* set our value if need */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
- if (retval > 0 && NULL != sk->sk_user_data && peer) {
+ /* set our value if need */
+ if (retval >= 0 && NULL != sk->sk_user_data && peer) {
+ if (sk_data_ready_addr == (unsigned long) sk->sk_data_ready &&
+ !sock_flag(sk, SOCK_NAT64)) {
+ memcpy(&tdata, &sk->sk_user_data, sizeof(tdata));
+ if (TCPOPT_TOA == tdata.opcode &&
+ TCPOLEN_IP4_TOA == tdata.opsize) {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_OK_CNT);
+ TOA_DBG("inet_getname_toa: set new sockaddr, ip "
+ TOA_NIPQUAD_FMT" -> "TOA_NIPQUAD_FMT
+ ", port %u -> %u\n",
+ TOA_NIPQUAD(sin->sin_addr.s_addr),
+ TOA_NIPQUAD(tdata.ip), ntohs(sin->sin_port),
+ ntohs(tdata.port));
+ sin->sin_port = tdata.port;
+ sin->sin_addr.s_addr = tdata.ip;
+ } else { /* sk_user_data doesn't belong to us */
+ TOA_INC_STATS(ext_stats,
+ GETNAME_TOA_MISMATCH_CNT);
+ TOA_DBG("inet_getname_toa: invalid toa data, "
+ "ip "TOA_NIPQUAD_FMT" port %u opcode %u "
+ "opsize %u\n",
+ TOA_NIPQUAD(tdata.ip), ntohs(tdata.port),
+ tdata.opcode, tdata.opsize);
+ }
+ } else {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_BYPASS_CNT);
+ }
+ } else { /* no need to get client ip */
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_EMPTY_CNT);
+ }
+
+ return retval;
+}
+
+/* NAT64 get client ip from socket
+ * Client ip is v6 and socket is v4
+ * Find toa and copy_to_user
+ * This function will not return inet_getname,
+ * so users can get distinctions from normal v4
+ *
+ * Notice:
+ * In fact, we can just use original api inet_getname_toa by uaddr_len judge.
+ * We didn't do this because RS developers may be confused about this api.
+ */
+#ifdef TOA_NAT64_ENABLE
+static int
+inet64_getname_toa(struct sock *sk, int cmd, void __user *user, int *len)
+{
+ struct inet_sock *inet;
+ struct toa_nat64_peer uaddr;
+ int ret;
+
+ if (cmd != TOA_SO_GET_LOOKUP || !sk) {
+ TOA_INFO("%s: bad cmd\n", __func__);
+ return -EINVAL;
+ }
+
+ if (*len < sizeof(struct toa_nat64_peer) ||
+ NULL == user) {
+ TOA_INFO("%s: bad param len\n", __func__);
+ return -EINVAL;
+ }
+
+ inet = inet_sk(sk);
+ /* refered to inet_getname */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ if (!inet->inet_dport ||
+#else
+ if (!inet->dport ||
+#endif
+ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)))
+ return -ENOTCONN;
+
+ ret = -EINVAL;
+
+ lock_cpu_toa_ip6_sk();
+
+ if (NULL != sk->sk_user_data) {
+ struct toa_ip6_entry *ptr_ip6_entry;
+ struct toa_ip6_data *ptr_ip6_data;
+
+ if (sk_data_ready_addr == (unsigned long) sk->sk_data_ready) {
+
+ if (!sock_flag(sk, SOCK_NAT64)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ptr_ip6_entry = sk->sk_user_data;
+ ptr_ip6_data = &ptr_ip6_entry->toa_data;
+
+ if (TCPOPT_TOA == ptr_ip6_data->opcode &&
+ TCPOLEN_IP6_TOA == ptr_ip6_data->opsize) {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_OK_CNT);
+ TOA_DBG("inet64_getname_toa: set new sockaddr, ip "
+ TOA_NIPQUAD_FMT" -> "TOA_NIP6_FMT
+ ", port %u -> %u\n",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ TOA_NIPQUAD(inet->inet_saddr),
#else
- if (retval == 0 && NULL != sk->sk_user_data && peer) {
-#endif
- if (sk_data_ready_addr == (unsigned long) sk->sk_data_ready) {
- memcpy(&tdata, &sk->sk_user_data, sizeof(tdata));
- if (TCPOPT_TOA == tdata.opcode &&
- TCPOLEN_TOA == tdata.opsize) {
- TOA_INC_STATS(ext_stats, GETNAME_TOA_OK_CNT);
- TOA_DBG("inet_getname_toa: set new sockaddr, "
- "ip %u.%u.%u.%u -> %u.%u.%u.%u, port "
- "%u -> %u\n",
- NIPQUAD(sin->sin_addr.s_addr),
- NIPQUAD(tdata.ip), ntohs(sin->sin_port),
- ntohs(tdata.port));
- sin->sin_port = tdata.port;
- sin->sin_addr.s_addr = tdata.ip;
- } else { /* sk_user_data doesn't belong to us */
- TOA_INC_STATS(ext_stats,
- GETNAME_TOA_MISMATCH_CNT);
- TOA_DBG("inet_getname_toa: invalid toa data, "
- "ip %u.%u.%u.%u port %u opcode %u "
- "opsize %u\n",
- NIPQUAD(tdata.ip), ntohs(tdata.port),
- tdata.opcode, tdata.opsize);
- }
- } else {
- TOA_INC_STATS(ext_stats, GETNAME_TOA_BYPASS_CNT);
- }
- } else { /* no need to get client ip */
- TOA_INC_STATS(ext_stats, GETNAME_TOA_EMPTY_CNT);
- }
-
- return retval;
+ TOA_NIPQUAD(inet->saddr),
+#endif
+ TOA_NIP6(ptr_ip6_data->in6_addr),
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ ntohs(inet->inet_sport),
+#else
+ ntohs(inet->sport),
+#endif
+ ntohs(ptr_ip6_data->port));
+ uaddr.saddr = ptr_ip6_data->in6_addr;
+ uaddr.port = ptr_ip6_data->port;
+
+ if (copy_to_user(user, &uaddr,
+ sizeof(struct toa_nat64_peer)) != 0) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *len = sizeof(struct toa_nat64_peer);
+ ret = 0;
+ goto out;
+ } else {
+ TOA_INC_STATS(ext_stats,
+ GETNAME_TOA_MISMATCH_CNT);
+ }
+ } else {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_BYPASS_CNT);
+ }
+ } else {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_EMPTY_CNT);
+ }
+
+out:
+ unlock_cpu_toa_ip6_sk();
+ return ret;
}
+#endif
-#ifdef CONFIG_IP_VS_TOA_IPV6
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
+#ifdef TOA_IPV6_ENABLE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,1)
static int
inet6_getname_toa(struct socket *sock, struct sockaddr *uaddr,
- int peer)
+ int peer)
#else
static int
inet6_getname_toa(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
+ int *uaddr_len, int peer)
#endif
{
- int retval = 0;
- struct sock *sk = sock->sk;
- struct sockaddr_in6 *sin = (struct sockaddr_in6 *) uaddr;
- struct toa_data tdata;
+ int retval = 0;
+ struct sock *sk = sock->sk;
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *) uaddr;
- TOA_DBG("inet6_getname_toa called, sk->sk_user_data is %p\n",
- sk->sk_user_data);
+ TOA_DBG("inet6_getname_toa called, sk->sk_user_data is %p\n",
+ sk->sk_user_data);
- /* call orginal one */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
- retval = inet6_getname(sock, uaddr, peer);
+ /* call orginal one */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,1)
+ retval = inet6_getname(sock, uaddr, peer);
#else
- retval = inet6_getname(sock, uaddr, uaddr_len, peer);
+ retval = inet6_getname(sock, uaddr, uaddr_len, peer);
#endif
- /* set our value if need */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
- if (retval > 0 && NULL != sk->sk_user_data && peer) {
-#else
- if (retval == 0 && NULL != sk->sk_user_data && peer) {
-#endif
- if (sk_data_ready_addr == (unsigned long) sk->sk_data_ready) {
- memcpy(&tdata, &sk->sk_user_data, sizeof(tdata));
- if (TCPOPT_TOA == tdata.opcode &&
- TCPOLEN_TOA == tdata.opsize) {
- TOA_INC_STATS(ext_stats, GETNAME_TOA_OK_CNT);
- sin->sin6_port = tdata.port;
- ipv6_addr_set(&sin->sin6_addr, 0, 0,
- htonl(0x0000FFFF), tdata.ip);
- } else { /* sk_user_data doesn't belong to us */
- TOA_INC_STATS(ext_stats,
- GETNAME_TOA_MISMATCH_CNT);
- }
- } else {
- TOA_INC_STATS(ext_stats, GETNAME_TOA_BYPASS_CNT);
- }
- } else { /* no need to get client ip */
- TOA_INC_STATS(ext_stats, GETNAME_TOA_EMPTY_CNT);
- }
-
- return retval;
+ /* set our value if need */
+ lock_cpu_toa_ip6_sk();
+
+ if (retval >= 0 && NULL != sk->sk_user_data && peer) {
+ if (sk_data_ready_addr == (unsigned long) sk->sk_data_ready) {
+ struct toa_ip6_entry* ptr_ip6_entry = sk->sk_user_data;
+ struct toa_ip6_data* ptr_ip6_data = &ptr_ip6_entry->toa_data;
+
+ if (sk == ptr_ip6_entry->sk &&
+ TCPOPT_TOA == ptr_ip6_data->opcode &&
+ TCPOLEN_IP6_TOA == ptr_ip6_data->opsize) {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_OK_CNT);
+ TOA_DBG("inet6_getname_toa: set new sockaddr, ip "
+ TOA_NIP6_FMT" -> "TOA_NIP6_FMT
+ ", port %u -> %u\n",
+ TOA_NIP6(sin->sin6_addr),
+ TOA_NIP6(ptr_ip6_data->in6_addr),
+ ntohs(sin->sin6_port),
+ ntohs(ptr_ip6_data->port));
+ sin->sin6_port = ptr_ip6_data->port;
+ sin->sin6_addr = ptr_ip6_data->in6_addr;
+ } else { /* sk_user_data doesn't belong to us */
+ TOA_INC_STATS(ext_stats,
+ GETNAME_TOA_MISMATCH_CNT);
+ }
+ } else {
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_BYPASS_CNT);
+ }
+ } else { /* no need to get client ip */
+ TOA_INC_STATS(ext_stats, GETNAME_TOA_EMPTY_CNT);
+ }
+
+ unlock_cpu_toa_ip6_sk();
+
+ return retval;
+}
+
+static inline int
+get_kernel_ipv6_symbol(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+ kallsyms_lookup_name_t kallsyms_lookup_name;
+ kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
+#endif
+
+ inet6_stream_ops_p =
+ (struct proto_ops *)kallsyms_lookup_name("inet6_stream_ops");
+ if (inet6_stream_ops_p == NULL) {
+ TOA_INFO("CPU [%u] kallsyms_lookup_name cannot find symbol inet6_stream_ops\n",
+ smp_processor_id());
+
+ return -1;
+ }
+ ipv6_specific_p =
+ (struct inet_connection_sock_af_ops *)kallsyms_lookup_name("ipv6_specific");
+ if (ipv6_specific_p == NULL) {
+ TOA_INFO("CPU [%u] kallsyms_lookup_name cannot find symbol ipv6_specific\n",
+ smp_processor_id());
+ return -1;
+ }
+ tcp_v6_syn_recv_sock_org_pt =
+ (syn_recv_sock_func_pt)kallsyms_lookup_name("tcp_v6_syn_recv_sock");
+ if (tcp_v6_syn_recv_sock_org_pt == NULL) {
+ TOA_INFO("CPU [%u] kallsyms_lookup_name cannot find symbol tcp_v6_syn_recv_sock\n",
+ smp_processor_id());
+ return -1;
+ }
+ return 0;
}
#endif
@@ -330,65 +791,106 @@ inet6_getname_toa(struct socket *sock, struct sockaddr *uaddr,
* @param dst [out] route cache entry
* @return NULL if fail new socket if succeed.
*/
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
- static struct sock *
- tcp_v4_syn_recv_sock_toa(const struct sock *sk, struct sk_buff *skb,
- struct request_sock *req,
- struct dst_entry *dst,
- struct request_sock *req_unhash,
- bool *own_req)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1)
+static struct sock *
+tcp_v4_syn_recv_sock_toa(const struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst,
+ struct request_sock *req_unhash,
+ bool *own_req)
#else
static struct sock *
tcp_v4_syn_recv_sock_toa(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req, struct dst_entry *dst)
+ struct request_sock *req, struct dst_entry *dst)
#endif
{
- struct sock *newsock = NULL;
+ struct sock *newsock = NULL;
+ int nat64 = 0;
- TOA_DBG("tcp_v4_syn_recv_sock_toa called\n");
+ TOA_DBG("tcp_v4_syn_recv_sock_toa called\n");
- /* call orginal one */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
- newsock = tcp_v4_syn_recv_sock(sk, skb, req, dst, req_unhash, own_req);
+ /* call orginal one */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1)
+ newsock = tcp_v4_syn_recv_sock(sk, skb, req, dst, req_unhash, own_req);
#else
- newsock = tcp_v4_syn_recv_sock(sk, skb, req, dst);
-#endif
-
- /* set our value if need */
- if (NULL != newsock && NULL == newsock->sk_user_data) {
- newsock->sk_user_data = get_toa_data(skb);
- if (NULL != newsock->sk_user_data)
- TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_TOA_CNT);
- else
- TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_NO_TOA_CNT);
- TOA_DBG("tcp_v4_syn_recv_sock_toa: set "
- "sk->sk_user_data to %p\n",
- newsock->sk_user_data);
- }
- return newsock;
+ newsock = tcp_v4_syn_recv_sock(sk, skb, req, dst);
+#endif
+
+ /* set our value if need */
+ if (NULL != newsock && NULL == newsock->sk_user_data) {
+ newsock->sk_user_data = get_toa_data(AF_INET, skb, &nat64);
+ sock_reset_flag(newsock, SOCK_NAT64);
+ if (NULL != newsock->sk_user_data) {
+ TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_TOA_CNT);
+#ifdef TOA_NAT64_ENABLE
+ if (nat64) {
+ struct toa_ip6_entry *ptr_ip6_entry = newsock->sk_user_data;
+ ptr_ip6_entry->sk = newsock;
+ toa_ip6_hash(ptr_ip6_entry);
+
+ newsock->sk_destruct = tcp_v6_sk_destruct_toa;
+
+ sock_set_flag(newsock, SOCK_NAT64);
+ }
+#endif
+ }
+ else
+ TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_NO_TOA_CNT);
+
+ TOA_DBG("tcp_v4_syn_recv_sock_toa: set "
+ "sk->sk_user_data to %p\n",
+ newsock->sk_user_data);
+ }
+ return newsock;
}
-#ifdef CONFIG_IP_VS_TOA_IPV6
+#ifdef TOA_IPV6_ENABLE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1)
+static struct sock *
+tcp_v6_syn_recv_sock_toa(const struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst,
+ struct request_sock *req_unhash,
+ bool *own_req)
+#else
static struct sock *
tcp_v6_syn_recv_sock_toa(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req, struct dst_entry *dst)
+ struct request_sock *req, struct dst_entry *dst)
+#endif
{
- struct sock *newsock = NULL;
-
- TOA_DBG("tcp_v4_syn_recv_sock_toa called\n");
-
- /* call orginal one */
- newsock = tcp_v6_syn_recv_sock(sk, skb, req, dst);
-
- /* set our value if need */
- if (NULL != newsock && NULL == newsock->sk_user_data) {
- newsock->sk_user_data = get_toa_data(skb);
- if (NULL != newsock->sk_user_data)
- TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_TOA_CNT);
- else
- TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_NO_TOA_CNT);
- }
- return newsock;
+ struct sock *newsock = NULL;
+ int nat64 = 0;
+
+ TOA_DBG("tcp_v6_syn_recv_sock_toa called\n");
+
+ /* call orginal one */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,1)
+ newsock = tcp_v6_syn_recv_sock_org_pt(sk, skb, req, dst, req_unhash,
+ own_req);
+#else
+ newsock = tcp_v6_syn_recv_sock_org_pt(sk, skb, req, dst);
+#endif
+
+ /* set our value if need */
+ if (NULL != newsock && NULL == newsock->sk_user_data) {
+ newsock->sk_user_data = get_toa_data(AF_INET6, skb, &nat64);
+ sock_reset_flag(newsock, SOCK_NAT64);
+ if (NULL != newsock->sk_user_data) {
+ struct toa_ip6_entry *ptr_ip6_entry = newsock->sk_user_data;
+ ptr_ip6_entry->sk = newsock;
+ toa_ip6_hash(ptr_ip6_entry);
+
+ newsock->sk_destruct = tcp_v6_sk_destruct_toa;
+ TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_TOA_CNT);
+ } else {
+ TOA_INC_STATS(ext_stats, SYN_RECV_SOCK_NO_TOA_CNT);
+ }
+
+ TOA_DBG("tcp_v6_syn_recv_sock_toa: set "
+ "sk->sk_user_data to %p\n",
+ newsock->sk_user_data);
+ }
+ return newsock;
}
#endif
@@ -400,179 +902,136 @@ tcp_v6_syn_recv_sock_toa(struct sock *sk, struct sk_buff *skb,
static inline int
hook_toa_functions(void)
{
-#if defined(CONFIG_ARM64)
- int err = 0;
-#else
- unsigned int level;
- pte_t *pte;
-#endif
-
- /* hook inet_getname for ipv4 */
- struct proto_ops *inet_stream_ops_p =
- (struct proto_ops *)&inet_stream_ops;
- /* hook tcp_v4_syn_recv_sock for ipv4 */
- struct inet_connection_sock_af_ops *ipv4_specific_p =
- (struct inet_connection_sock_af_ops *)&ipv4_specific;
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- /* hook inet6_getname for ipv6 */
- struct proto_ops *inet6_stream_ops_p =
- (struct proto_ops *)&inet6_stream_ops;
- /* hook tcp_v6_syn_recv_sock for ipv6 */
- struct inet_connection_sock_af_ops *ipv6_specific_p =
- (struct inet_connection_sock_af_ops *)&ipv6_specific;
-#endif
-
-#if defined(CONFIG_ARM64)
- err |= toa_mkwrite((unsigned long)&inet_stream_ops_p->getname);
- err |= toa_mkwrite((unsigned long)&ipv4_specific_p->syn_recv_sock);
-#ifdef CONFIG_IP_VS_TOA_IPV6
- err |= toa_mkwrite((unsigned long)&inet6_stream_ops_p->getname);
- err |= toa_mkwrite((unsigned long)&ipv6_specific_p->syn_recv_sock);
-#endif
- if (0 == err) {
- flush_tlb_all();
- } else {
- return 1;
- }
-#else
- pte = lookup_address((unsigned long )inet_stream_ops_p, &level);
- if (pte == NULL)
- return 1;
- if (pte->pte & ~_PAGE_RW) {
- pte->pte |= _PAGE_RW;
- }
-#endif
- /*TOA_INFO("CPU [%u] hooked before inet_getname <%p> --> <%p>\n",
- smp_processor_id(), inet_getname, inet_getname_toa);*/
-
- inet_stream_ops_p->getname = inet_getname_toa;
- TOA_INFO("CPU [%u] hooked inet_getname <%p> --> <%p>, <%p>\n",
- smp_processor_id(), inet_getname, inet_stream_ops_p->getname, inet_getname_toa);
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- inet6_stream_ops_p->getname = inet6_getname_toa;
- TOA_INFO("CPU [%u] hooked inet6_getname <%p> --> <%p>\n",
- smp_processor_id(), inet6_getname, inet6_stream_ops_p->getname);
-#endif
-
- ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock_toa;
- TOA_INFO("CPU [%u] hooked tcp_v4_syn_recv_sock <%p> --> <%p>, <%p>\n",
- smp_processor_id(), tcp_v4_syn_recv_sock,
- ipv4_specific_p->syn_recv_sock,
- tcp_v4_syn_recv_sock_toa);
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- ipv6_specific_p->syn_recv_sock = tcp_v6_syn_recv_sock_toa;
- TOA_INFO("CPU [%u] hooked tcp_v6_syn_recv_sock <%p> --> <%p>\n",
- smp_processor_id(), tcp_v6_syn_recv_sock,
- ipv6_specific_p->syn_recv_sock);
-#endif
-#if defined(CONFIG_ARM64)
- toa_wrprotect((unsigned long)&inet_stream_ops_p->getname);
- toa_wrprotect((unsigned long)&ipv4_specific_p->syn_recv_sock);
-#ifdef CONFIG_IP_VS_TOA_IPV6
- toa_wrprotect((unsigned long)&inet6_stream_ops_p->getname);
- toa_wrprotect((unsigned long)&ipv6_specific_p->syn_recv_sock);
-#endif
- flush_tlb_all();
-#else
- pte = lookup_address((unsigned long )inet_stream_ops_p, &level);
- if (pte == NULL)
- return 1;
- pte->pte |= pte->pte &~_PAGE_RW;
+ struct proto_ops *inet_stream_ops_p;
+ struct inet_connection_sock_af_ops *ipv4_specific_p;
+ int rw_enable = 0;
+
+ /* hook inet_getname for ipv4 */
+ inet_stream_ops_p = (struct proto_ops *)&inet_stream_ops;
+
+ if (is_ro_addr((unsigned long)(&inet_stream_ops.getname))) {
+ set_addr_rw((unsigned long)(&inet_stream_ops.getname));
+ rw_enable = 1;
+ }
+ inet_stream_ops_p->getname = inet_getname_toa;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&inet_stream_ops.getname));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] hooked inet_getname <%p> --> <%p>\n",
+ smp_processor_id(), inet_getname, inet_stream_ops_p->getname);
+
+ ipv4_specific_p = (struct inet_connection_sock_af_ops *)&ipv4_specific;
+
+ if (is_ro_addr((unsigned long)(&ipv4_specific.syn_recv_sock))) {
+ set_addr_rw((unsigned long)(&ipv4_specific.syn_recv_sock));
+ rw_enable = 1;
+ }
+ ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock_toa;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&ipv4_specific.syn_recv_sock));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] hooked tcp_v4_syn_recv_sock <%p> --> <%p>\n",
+ smp_processor_id(), tcp_v4_syn_recv_sock,
+ ipv4_specific_p->syn_recv_sock);
+#ifdef TOA_IPV6_ENABLE
+ if (is_ro_addr((unsigned long)(&inet6_stream_ops_p->getname))) {
+ set_addr_rw((unsigned long)(&inet6_stream_ops_p->getname));
+ rw_enable = 1;
+ }
+ inet6_stream_ops_p->getname = inet6_getname_toa;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&inet6_stream_ops_p->getname));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] hooked inet6_getname <%p> --> <%p>\n",
+ smp_processor_id(), inet6_getname, inet6_stream_ops_p->getname);
+
+ if (is_ro_addr((unsigned long)(&ipv6_specific_p->syn_recv_sock))) {
+ set_addr_rw((unsigned long)(&ipv6_specific_p->syn_recv_sock));
+ rw_enable = 1;
+ }
+ ipv6_specific_p->syn_recv_sock = tcp_v6_syn_recv_sock_toa;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&ipv6_specific_p->syn_recv_sock));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] hooked tcp_v6_syn_recv_sock <%p> --> <%p>\n",
+ smp_processor_id(), tcp_v6_syn_recv_sock_org_pt,
+ ipv6_specific_p->syn_recv_sock);
#endif
- return 0;
+ return 0;
}
/* replace the functions to original ones */
static int
unhook_toa_functions(void)
{
-#if defined(CONFIG_ARM64)
- int err = 0;
-#else
- unsigned int level;
- pte_t *pte;
-#endif
-
- /* unhook inet_getname for ipv4 */
- struct proto_ops *inet_stream_ops_p =
- (struct proto_ops *)&inet_stream_ops;
- /* unhook tcp_v4_syn_recv_sock for ipv4 */
- struct inet_connection_sock_af_ops *ipv4_specific_p =
- (struct inet_connection_sock_af_ops *)&ipv4_specific;
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- /* unhook inet6_getname for ipv6 */
- struct proto_ops *inet6_stream_ops_p =
- (struct proto_ops *)&inet6_stream_ops;
- /* unhook tcp_v6_syn_recv_sock for ipv6 */
- struct inet_connection_sock_af_ops *ipv6_specific_p =
- (struct inet_connection_sock_af_ops *)&ipv6_specific;
-#endif
-
-#if defined(CONFIG_ARM64)
- err |= toa_mkwrite((unsigned long)&inet_stream_ops_p->getname);
- err |= toa_mkwrite((unsigned long)&ipv4_specific_p->syn_recv_sock);
-#ifdef CONFIG_IP_VS_TOA_IPV6
- err |= toa_mkwrite((unsigned long)&inet6_stream_ops_p->getname);
- err |= toa_mkwrite((unsigned long)&ipv6_specific_p->syn_recv_sock);
-#endif
- if (0 == err) {
- flush_tlb_all();
- } else {
- return 1;
- }
-#else
- pte = lookup_address((unsigned long )inet_stream_ops_p, &level);
- if (pte == NULL)
- return 1;
- if (pte->pte & ~_PAGE_RW) {
- pte->pte |= _PAGE_RW;
- }
-#endif
- /*TOA_INFO("CPU [%u] unhooked before inet_getname: %p\n",
- smp_processor_id(), inet_getname);*/
-
- inet_stream_ops_p->getname = inet_getname;
- TOA_INFO("CPU [%u] unhooked inet_getname\n",
- smp_processor_id());
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- inet6_stream_ops_p->getname = inet6_getname;
- TOA_INFO("CPU [%u] unhooked inet6_getname\n",
- smp_processor_id());
-#endif
- ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock;
- TOA_INFO("CPU [%u] unhooked tcp_v4_syn_recv_sock\n",
- smp_processor_id());
-
-#ifdef CONFIG_IP_VS_TOA_IPV6
- ipv6_specific_p->syn_recv_sock = tcp_v6_syn_recv_sock;
- TOA_INFO("CPU [%u] unhooked tcp_v6_syn_recv_sock\n",
- smp_processor_id());
+ struct proto_ops *inet_stream_ops_p;
+ struct inet_connection_sock_af_ops *ipv4_specific_p;
+ int rw_enable = 0;
+
+ /* unhook inet_getname for ipv4 */
+ inet_stream_ops_p = (struct proto_ops *)&inet_stream_ops;
+
+ if (is_ro_addr((unsigned long)(&inet_stream_ops.getname))) {
+ set_addr_rw((unsigned long)(&inet_stream_ops.getname));
+ rw_enable = 1;
+ }
+ inet_stream_ops_p->getname = inet_getname;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&inet_stream_ops.getname));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] unhooked inet_getname\n", smp_processor_id());
+
+ /* unhook tcp_v4_syn_recv_sock for ipv4 */
+ ipv4_specific_p = (struct inet_connection_sock_af_ops *)&ipv4_specific;
+ if (is_ro_addr((unsigned long)(&ipv4_specific.syn_recv_sock))) {
+ set_addr_rw((unsigned long)(&ipv4_specific.syn_recv_sock));
+ rw_enable = 1;
+ }
+ set_addr_rw((unsigned long)(&ipv4_specific.syn_recv_sock));
+ ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&ipv4_specific.syn_recv_sock));
+ rw_enable = 0;
+ }
+
+ TOA_INFO("CPU [%u] unhooked tcp_v4_syn_recv_sock\n", smp_processor_id());
+
+#ifdef TOA_IPV6_ENABLE
+ if (inet6_stream_ops_p) {
+ if (is_ro_addr((unsigned long)(&inet6_stream_ops_p->getname))) {
+ set_addr_rw((unsigned long)(&inet6_stream_ops_p->getname));
+ rw_enable = 1;
+ }
+ inet6_stream_ops_p->getname = inet6_getname;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&inet6_stream_ops_p->getname));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] unhooked inet6_getname\n", smp_processor_id());
+ }
+ if (ipv6_specific_p) {
+ if (is_ro_addr((unsigned long)(&ipv6_specific_p->syn_recv_sock))) {
+ set_addr_rw((unsigned long)(&ipv6_specific_p->syn_recv_sock));
+ rw_enable = 1;
+ }
+ ipv6_specific_p->syn_recv_sock = tcp_v6_syn_recv_sock_org_pt;
+ if (rw_enable == 1) {
+ set_addr_ro((unsigned long)(&ipv6_specific_p->syn_recv_sock));
+ rw_enable = 0;
+ }
+ TOA_INFO("CPU [%u] unhooked tcp_v6_syn_recv_sock\n", smp_processor_id());
+ }
#endif
-#if defined(CONFIG_ARM64)
- toa_wrprotect((unsigned long)&inet_stream_ops_p->getname);
- toa_wrprotect((unsigned long)&ipv4_specific_p->syn_recv_sock);
-#ifdef CONFIG_IP_VS_TOA_IPV6
- toa_wrprotect((unsigned long)&inet6_stream_ops_p->getname);
- toa_wrprotect((unsigned long)&ipv6_specific_p->syn_recv_sock);
-#endif
- flush_tlb_all();
-#else
- pte = lookup_address((unsigned long )inet_stream_ops_p, &level);
- if (pte == NULL)
- return 1;
- pte->pte |= pte->pte &~_PAGE_RW;
-#endif
-
- return 0;
+ return 0;
}
/*
@@ -580,120 +1039,188 @@ unhook_toa_functions(void)
*/
static int toa_stats_show(struct seq_file *seq, void *v)
{
- int i, j, cpu_nr;
-
- /* print CPU first */
- seq_printf(seq, " ");
- cpu_nr = num_possible_cpus();
- for (i = 0; i < cpu_nr; i++)
- if (cpu_online(i))
- seq_printf(seq, "CPU%d ", i);
- seq_putc(seq, '\n');
-
- i = 0;
- while (NULL != toa_stats[i].name) {
- seq_printf(seq, "%-25s:", toa_stats[i].name);
- for (j = 0; j < cpu_nr; j++) {
- if (cpu_online(j)) {
- seq_printf(seq, "%10lu ", *(
- ((unsigned long *) per_cpu_ptr(
- ext_stats, j)) + toa_stats[i].entry
- ));
- }
- }
- seq_putc(seq, '\n');
- i++;
- }
- return 0;
+ int i, j, cpu_nr;
+
+ /* print CPU first */
+ seq_printf(seq, " ");
+ cpu_nr = num_possible_cpus();
+ for (i = 0; i < cpu_nr; i++)
+ if (cpu_online(i))
+ seq_printf(seq, "CPU%d ", i);
+ seq_putc(seq, '\n');
+
+ i = 0;
+ while (NULL != toa_stats[i].name) {
+ seq_printf(seq, "%-25s:", toa_stats[i].name);
+ for (j = 0; j < cpu_nr; j++) {
+ if (cpu_online(j)) {
+ seq_printf(seq, "%10lu ", *(
+ ((unsigned long *) per_cpu_ptr(
+ ext_stats, j)) + toa_stats[i].entry
+ ));
+ }
+ }
+ seq_putc(seq, '\n');
+ i++;
+ }
+ return 0;
}
static int toa_stats_seq_open(struct inode *inode, struct file *file)
{
- return single_open(file, toa_stats_show, NULL);
+ return single_open(file, toa_stats_show, NULL);
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
static const struct proc_ops toa_stats_fops = {
- .proc_open = toa_stats_seq_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
+ .proc_open = toa_stats_seq_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
};
#else
static const struct file_operations toa_stats_fops = {
- .owner = THIS_MODULE,
- .open = toa_stats_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
+ .owner = THIS_MODULE,
+ .open = toa_stats_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+#ifdef TOA_NAT64_ENABLE
+static struct nf_sockopt_ops toa_sockopts = {
+ .pf = PF_INET,
+ .owner = THIS_MODULE,
+ /* Nothing to do in set */
+ /* get */
+ .get_optmin = TOA_BASE_CTL,
+ .get_optmax = TOA_SO_GET_MAX+1,
+ .get = inet64_getname_toa,
};
#endif
/*
* TOA module init and destory
*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
+static struct proc_dir_entry *proc_net_fops_create(struct net *net,
+ const char *name, mode_t mode, const struct proc_ops *proc_ops)
+{
+ return proc_create(name, mode, net->proc_net, proc_ops);
+}
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
+static struct proc_dir_entry *proc_net_fops_create(struct net *net,
+ const char *name, mode_t mode, const struct file_operations *fops)
+{
+ return proc_create(name, mode, net->proc_net, fops);
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
+static void proc_net_remove(struct net *net, const char *name)
+{
+ remove_proc_entry(name, net->proc_net);
+}
+#endif
/* module init */
static int __init
toa_init(void)
{
- int ret = -1;
-
- ret = toa_get_kallsyms_lookup_name_addr();
- if (ret < 0) {
- return 1;
- }
-
- /* alloc statistics array for toa */
- ext_stats = alloc_percpu(struct toa_stat_mib);
- if (NULL == ext_stats)
- return 1;
- proc_create("toa_stats", 0, init_net.proc_net, &toa_stats_fops);
-
- /* get the address of function sock_def_readable
- * so later we can know whether the sock is for rpc, tux or others
- */
- sk_data_ready_addr = kallsyms_lookup_name_fun("sock_def_readable");
- TOA_INFO("CPU [%u] sk_data_ready_addr = "
- "kallsyms_lookup_name(sock_def_readable) = %lu\n",
- smp_processor_id(), sk_data_ready_addr);
- if (0 == sk_data_ready_addr) {
- TOA_INFO("cannot find sock_def_readable.\n");
- goto err;
- }
-
- /* hook funcs for parse and get toa */
- if (0 != hook_toa_functions()) {
- TOA_INFO("cannot hook toa functions.\n");
- goto err;
- }
-
- TOA_INFO("toa loaded\n");
- return 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+ kallsyms_lookup_name_t kallsyms_lookup_name;
+ int ret = register_kprobe(&kp);
+ if (ret < 0) {
+ TOA_INFO("register_kprobe failed, returned %d\n", ret);
+ return 1;
+ }
+ kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
+#endif
+
+ TOA_INFO("TOA " TOA_VERSION " by qlb of iqiyi.\n");
+
+ /* alloc statistics array for toa */
+ ext_stats = alloc_percpu(struct toa_stat_mib);
+ if (NULL == ext_stats)
+ return 1;
+ proc_net_fops_create(&init_net, "toa_stats", 0, &toa_stats_fops);
+
+ /* get the address of function sock_def_readable
+ * so later we can know whether the sock is for rpc, tux or others
+ */
+ sk_data_ready_addr = kallsyms_lookup_name("sock_def_readable");
+ TOA_INFO("CPU [%u] sk_data_ready_addr = "
+ "kallsyms_lookup_name(sock_def_readable) = %lu\n",
+ smp_processor_id(), sk_data_ready_addr);
+ if (0 == sk_data_ready_addr) {
+ TOA_INFO("cannot find sock_def_readable.\n");
+ goto err;
+ }
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+ if (0 != init_toa_ip6()) {
+ TOA_INFO("init toa ip6 fail.\n");
+ goto err;
+ }
+#endif
+
+#ifdef TOA_IPV6_ENABLE
+ if (0 != get_kernel_ipv6_symbol()) {
+ TOA_INFO("get ipv6 struct from kernel fail.\n");
+ goto err;
+ }
+#endif
+
+#ifdef TOA_NAT64_ENABLE
+ if (0 != nf_register_sockopt(&toa_sockopts)) {
+ TOA_INFO("fail to register sockopt\n");
+ goto err;
+ }
+#endif
+
+ /* hook funcs for parse and get toa */
+ hook_toa_functions();
+
+ TOA_INFO("toa loaded\n");
+ return 0;
err:
- remove_proc_entry("toa_stats",init_net.proc_net);
- if (NULL != ext_stats) {
- free_percpu(ext_stats);
- ext_stats = NULL;
- }
+ proc_net_remove(&init_net, "toa_stats");
+ if (NULL != ext_stats) {
+ free_percpu(ext_stats);
+ ext_stats = NULL;
+ }
- return 1;
+ return 1;
}
/* module cleanup*/
static void __exit
toa_exit(void)
{
- unhook_toa_functions();
- synchronize_net();
-
- remove_proc_entry("toa_stats",init_net.proc_net);
- if (NULL != ext_stats) {
- free_percpu(ext_stats);
- ext_stats = NULL;
- }
- TOA_INFO("toa unloaded\n");
+ unhook_toa_functions();
+#ifdef TOA_NAT64_ENABLE
+ nf_unregister_sockopt(&toa_sockopts);
+#endif
+ synchronize_net();
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+ if (0 != exit_toa_ip6()) {
+ TOA_INFO("exit toa ip6 fail.\n");
+ }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+ unregister_kprobe(&kp);
+#endif
+
+ proc_net_remove(&init_net, "toa_stats");
+ if (NULL != ext_stats) {
+ free_percpu(ext_stats);
+ ext_stats = NULL;
+ }
+ TOA_INFO("toa unloaded\n");
}
module_init(toa_init);
diff --git a/src/toa.h b/src/toa.h
index a46f82d..64095c3 100644
--- a/src/toa.h
+++ b/src/toa.h
@@ -1,3 +1,20 @@
+/*
+ * DPVS is a software load balancer (Virtual Server) based on DPDK.
+ *
+ * Copyright (C) 2021 iQIYI (www.iqiyi.com).
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
#ifndef __NET__TOA_H__
#define __NET__TOA_H__
@@ -19,78 +36,118 @@
#include <linux/kallsyms.h>
#include <net/ipv6.h>
#include <net/transp_v6.h>
+#include <net/sock.h>
+#include <linux/netfilter.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
+#include <linux/kprobes.h>
+#endif
#include <asm/tlbflush.h>
-#define TOA_VERSION "1.0.0.0"
+#define TOA_VERSION "2.0.0.0"
-#ifdef TOA_DBG_MSG
-#define TOA_DBG(msg...) \
- do { \
- printk(KERN_DEBUG "[DEBUG] TOA: " msg); \
- } while (0)
+#ifdef TOA_DEBUG_ENABLE
+#define TOA_DBG(msg...) \
+ do { \
+ printk(KERN_DEBUG "[DEBUG] TOA: " msg); \
+ } while (0)
#else
-#define TOA_DBG(msg...) (void)0
+#define TOA_DBG(msg...)
#endif
-#define TOA_INFO(msg...) \
- do { \
- if (net_ratelimit()) \
- printk(KERN_INFO "TOA: " msg); \
- } while (0)
+#define TOA_INFO(msg...) \
+ do { \
+ if (net_ratelimit()) \
+ printk(KERN_INFO "TOA: " msg); \
+ } while (0)
+
#define TCPOPT_TOA 254
/* MUST be 4n !!!! */
-#define TCPOLEN_TOA 8 /* |opcode|size|ip+port| = 1 + 1 + 6 */
+#define TCPOLEN_IP4_TOA 8 /* |opcode|size|ip+port| = 1 + 1 + 6 */
+#define TCPOLEN_IP6_TOA 20 /* |opcode|size|ip_of_v6+port| = 1 + 1 + 18 */
/* MUST be 4 bytes alignment */
-struct toa_data {
- __u8 opcode;
- __u8 opsize;
- __u16 port;
- __u32 ip;
+struct toa_ip4_data {
+ __u8 opcode;
+ __u8 opsize;
+ __u16 port;
+ __u32 ip;
+};
+
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+struct toa_ip6_data {
+ __u8 opcode;
+ __u8 opsize;
+ __u16 port;
+ struct in6_addr in6_addr;
+};
+#endif
+
+#ifdef TOA_NAT64_ENABLE
+struct toa_nat64_peer {
+ struct in6_addr saddr;
+ __u16 port;
+};
+
+/* toa socket options, now only for nat64 */
+enum {
+ TOA_BASE_CTL = 4096,
+ /* set */
+ TOA_SO_SET_MAX = TOA_BASE_CTL,
+ /* get */
+ TOA_SO_GET_LOOKUP = TOA_BASE_CTL,
+ TOA_SO_GET_MAX = TOA_SO_GET_LOOKUP,
+};
+#endif
+
+/*should be larger than enum sock_flags(net/sock.h)*/
+enum toa_sock_flags {
+#if defined(__x86_64__)
+ SOCK_NAT64 = 63
+#else
+ SOCK_NAT64 = 31
+#endif
};
/* statistics about toa in proc /proc/net/toa_stat */
enum {
- SYN_RECV_SOCK_TOA_CNT = 1,
- SYN_RECV_SOCK_NO_TOA_CNT,
- GETNAME_TOA_OK_CNT,
- GETNAME_TOA_MISMATCH_CNT,
- GETNAME_TOA_BYPASS_CNT,
- GETNAME_TOA_EMPTY_CNT,
- TOA_STAT_LAST
+ SYN_RECV_SOCK_TOA_CNT = 1,
+ SYN_RECV_SOCK_NO_TOA_CNT,
+ GETNAME_TOA_OK_CNT,
+ GETNAME_TOA_MISMATCH_CNT,
+ GETNAME_TOA_BYPASS_CNT,
+ GETNAME_TOA_EMPTY_CNT,
+#if (defined(TOA_IPV6_ENABLE) || defined(TOA_NAT64_ENABLE))
+ IP6_ADDR_ALLOC_CNT,
+ IP6_ADDR_FREE_CNT,
+#endif
+ TOA_STAT_LAST
};
struct toa_stats_entry {
- char *name;
- int entry;
+ char *name;
+ int entry;
};
#define TOA_STAT_ITEM(_name, _entry) { \
- .name = _name, \
- .entry = _entry, \
+ .name = _name, \
+ .entry = _entry, \
}
-#define TOA_STAT_END { \
- NULL, \
- 0, \
+#define TOA_STAT_END { \
+ NULL, \
+ 0, \
}
struct toa_stat_mib {
- unsigned long mibs[TOA_STAT_LAST];
+ unsigned long mibs[TOA_STAT_LAST];
};
-#define NIPQUAD(addr) \
- ((unsigned char *)&addr)[0], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[3]
-
#define DEFINE_TOA_STAT(type, name) \
- (__typeof__(type) *name)
+ __typeof__(type) *name
#define TOA_INC_STATS(mib, field) \
- (per_cpu_ptr(mib, smp_processor_id())->mibs[field]++)
+ (per_cpu_ptr(mib, smp_processor_id())->mibs[field]++)
#endif
--
2.27.0