blob: 9e937af5ad36c586978c0875539cb38b8376db9b [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
8#include <net/gre.h>
9
10#include <pce/cls.h>
developer15ee46c2023-08-24 16:35:34 +080011#include <pce/netsys.h>
developere5e687d2023-08-08 16:05:33 +080012#include <pce/pce.h>
13
14#include "tunnel.h"
15
developer15ee46c2023-08-24 16:35:34 +080016static int gretap_cls_entry_setup(struct tops_tnl_info *tnl_info,
17 struct cls_desc *cdesc)
18{
19 CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
20 CLS_DESC_DATA(cdesc, tport_idx, 0x4);
21 CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_HDR);
22 CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
23 CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_GRE);
24 CLS_DESC_MASK_DATA(cdesc, l4_udp_hdr_nez,
25 CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK,
26 CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK);
27 CLS_DESC_MASK_DATA(cdesc, l4_valid,
28 CLS_DESC_L4_VALID_MASK,
29 CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
30 CLS_DESC_VALID_LOWER_HALF_WORD_BIT);
31 CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x0000FFFF, 0x00006558);
32
33 return 0;
34}
developere5e687d2023-08-08 16:05:33 +080035
36static int gretap_tnl_decap_param_setup(struct sk_buff *skb,
37 struct tops_tnl_params *tnl_params)
38{
39 struct gre_base_hdr *pgre;
40 struct gre_base_hdr greh;
41 struct ethhdr *eth;
42 struct ethhdr ethh;
43 struct iphdr *ip;
44 struct iphdr iph;
45 int ret = 0;
46
47 if (!skb->dev->rtnl_link_ops
48 || strcmp(skb->dev->rtnl_link_ops->kind, "gretap"))
49 return -EAGAIN;
50
51 skb_push(skb, sizeof(struct gre_base_hdr));
52 pgre = skb_header_pointer(skb, 0, sizeof(struct gre_base_hdr), &greh);
53 if (unlikely(!pgre)) {
54 ret = -EINVAL;
55 goto restore_gre;
56 }
57
58 if (unlikely(ntohs(pgre->protocol) != ETH_P_TEB)) {
59 pr_notice("gre: %p protocol unmatched, proto: 0x%x\n",
60 pgre, ntohs(pgre->protocol));
61 ret = -EINVAL;
62 goto restore_gre;
63 }
64
65 /* TODO: store gre parameters? */
66
67 skb_push(skb, sizeof(struct iphdr));
68 ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
69 if (unlikely(!ip)) {
70 ret = -EINVAL;
71 goto restore_ip;
72 }
73
74 if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_GRE)) {
75 pr_notice("ip: %p version or protocol unmatched, ver: 0x%x, proto: 0x%x\n",
76 ip, ip->version, ip->protocol);
77 ret = -EINVAL;
78 goto restore_ip;
79 }
80
81 /* TODO: check ip options is support for us? */
82 /* TODO: store ip parameters? */
83 tnl_params->protocol = ip->protocol;
84 tnl_params->sip = ip->daddr;
85 tnl_params->dip = ip->saddr;
86
87 skb_push(skb, sizeof(struct ethhdr));
88 eth = skb_header_pointer(skb, 0, sizeof(struct ethhdr), &ethh);
89 if (unlikely(!eth)) {
90 ret = -EINVAL;
91 goto restore_eth;
92 }
93
94 if (unlikely(ntohs(eth->h_proto) != ETH_P_IP)) {
95 pr_notice("eth proto not support, proto: 0x%x\n",
96 ntohs(eth->h_proto));
97 ret = -EINVAL;
98 goto restore_eth;
99 }
100
101 memcpy(&tnl_params->saddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
102 memcpy(&tnl_params->daddr, eth->h_source, sizeof(u8) * ETH_ALEN);
103
104restore_eth:
105 skb_pull(skb, sizeof(struct ethhdr));
106
107restore_ip:
108 skb_pull(skb, sizeof(struct iphdr));
109
110restore_gre:
111 skb_pull(skb, sizeof(struct gre_base_hdr));
112
113 return ret;
114}
115
116static int gretap_tnl_encap_param_setup(struct sk_buff *skb,
117 struct tops_tnl_params *tnl_params)
118{
119 struct ethhdr *eth = eth_hdr(skb);
120 struct iphdr *ip = ip_hdr(skb);
121
122 /*
123 * ether type no need to check since it is even not constructed yet
124 * currently not support gre without ipv4
125 */
126 if (unlikely(ip->version != IPVERSION || ip->protocol != IPPROTO_GRE)) {
127 pr_notice("eth proto: 0x%x, ip ver: 0x%x, proto: 0x%x is not support\n",
128 ntohs(eth->h_proto),
129 ip->version,
130 ip->protocol);
131 return -EINVAL;
132 }
133
134 memcpy(&tnl_params->saddr, eth->h_source, sizeof(u8) * ETH_ALEN);
135 memcpy(&tnl_params->daddr, eth->h_dest, sizeof(u8) * ETH_ALEN);
136 tnl_params->protocol = ip->protocol;
137 tnl_params->sip = ip->saddr;
138 tnl_params->dip = ip->daddr;
139
140 return 0;
141}
142
143static int gretap_tnl_debug_param_setup(const char *buf, int *ofs,
144 struct tops_tnl_params *tnl_params)
145{
146 tnl_params->protocol = IPPROTO_GRE;
147 return 0;
148}
149
150static bool gretap_tnl_info_match(struct tops_tnl_params *parms1,
151 struct tops_tnl_params *parms2)
152{
153 if (parms1->sip == parms2->sip
154 && parms1->dip == parms2->dip
155 && !memcmp(parms1->saddr, parms2->saddr, sizeof(u8) * ETH_ALEN)
156 && !memcmp(parms1->daddr, parms2->daddr, sizeof(u8) * ETH_ALEN)) {
157 return true;
158 }
159
160 return false;
161}
162
163static bool gretap_tnl_decap_offloadable(struct sk_buff *skb)
164{
165 struct iphdr *ip = ip_hdr(skb);
166
167 if (ip->protocol != IPPROTO_GRE)
168 return false;
169
170 return true;
171}
172
173static struct tops_tnl_type gretap_type = {
174 .type_name = "gretap",
developer15ee46c2023-08-24 16:35:34 +0800175 .cls_entry_setup = gretap_cls_entry_setup,
developere5e687d2023-08-08 16:05:33 +0800176 .tnl_decap_param_setup = gretap_tnl_decap_param_setup,
177 .tnl_encap_param_setup = gretap_tnl_encap_param_setup,
178 .tnl_debug_param_setup = gretap_tnl_debug_param_setup,
179 .tnl_info_match = gretap_tnl_info_match,
180 .tnl_decap_offloadable = gretap_tnl_decap_offloadable,
181 .tops_entry = TOPS_ENTRY_GRETAP,
182 .has_inner_eth = true,
183};
184
185int mtk_tops_gretap_init(void)
186{
developer15ee46c2023-08-24 16:35:34 +0800187 return mtk_tops_tnl_type_register(&gretap_type);
developere5e687d2023-08-08 16:05:33 +0800188}
189
190void mtk_tops_gretap_deinit(void)
191{
developere5e687d2023-08-08 16:05:33 +0800192 mtk_tops_tnl_type_unregister(&gretap_type);
193}