blob: 263b69a8c0daf3bd5f4157094f6b095f7e6c929d [file] [log] [blame]
Wayne Tanbb7f1782021-12-13 11:16:04 -08001/*
2 * sfe_vlan.h
3 * Shortcut flow acceleration for 802.1AD/802.1Q flow
4 *
5 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef __SFE_VLAN_H
21#define __SFE_VLAN_H
22
23#include <linux/if_vlan.h>
24
25/*
26 * sfe_vlan_check_and_parse_tag()
27 *
28 * case 1: QinQ frame (e.g. outer tag = 88a80032, inner tag = 81000001):
29 * When entering this function:
30 * ----+-----------------+-----|-----+-----------+-----+---------
31 * |DMAC |SMAC |88|a8|00|32|81|00|00|01|08|00|45|00|
32 * ----+-----------------+-----A-----+-----------+-----+---------
33 * skb->data
34 * skb->protocol = ntohs(ETH_P_8021AD)
35 * skb->vlan_proto = 0
36 * skb->vlan_tci = 0
37 * skb->vlan_present = 0
38 * When exiting:
39 * ----+-----------------+-----------+-----------+-----+---------
40 * |DMAC |SMAC |88|a8|00|32|81|00|00|01|08|00|45|00|
41 * ----+-----------------+-----------+-----------+-----A---------
42 * skb->data
43 * skb->protocol = ntohs(ETH_P_IP)
44 * skb->vlan_proto = 0
45 * skb->vlan_tci = 0
46 * skb->vlan_present = 0
47 * l2_info->vlan_hdr_cnt = 2
48 * l2_info->vlan_hdr[0].tpid = ntohs(ETH_P_8021AD)
49 * l2_info->vlan_hdr[0].tci = 0x0032
50 * l2_info->vlan_hdr[1].tpid = ntohs(ETH_P_8021Q)
51 * l2_info->vlan_hdr[1].tci = 0x0001
52 * l2_info->protocol = ETH_P_IP
53 *
54 * case 2: 802.1Q frame (e.g. the tag is 81000001):
55 * When entering this function:
56 * ----+-----------------+-----|-----+-----+---------
57 * |DMAC |SMAC |81|00|00|01|08|00|45|00|
58 * ----+-----------------+-----A-----+-----+---------
59 * skb->data
60 * skb->protocol = ntohs(ETH_P_8021Q)
61 * skb->vlan_proto = 0
62 * skb->vlan_tci = 0
63 * skb->vlan_present = 0
64 * When exiting:
65 * ----+-----------------+-----------+-----+---------
66 * |DMAC |SMAC |81|00|00|01|08|00|45|00|
67 * ----+-----------------+-----------+-----A---------
68 * skb->data
69 * skb->protocol = ntohs(ETH_P_IP)
70 * skb->vlan_proto = 0
71 * skb->vlan_tci = 0
72 * skb->vlan_present = 0
73 * l2_info->vlan_hdr_cnt = 1
74 * l2_info->vlan_hdr[0].tpid = ntohs(ETH_P_8021Q)
75 * l2_info->vlan_hdr[0].tci = 0x0001
76 * l2_info->protocol = ETH_P_IP
77 *
78 * case 3: untagged frame
79 * When entering this function:
80 * ----+-----------------+-----|---------------------
81 * |DMAC |SMAC |08|00|45|00|
82 * ----+-----------------+-----A---------------------
83 * skb->data
84 * skb->protocol = ntohs(ETH_P_IP)
85 * skb->vlan_proto = 0
86 * skb->vlan_tci = 0
87 * skb->vlan_present = 0
88 * When exiting:
89 * ----+-----------------+-----|---------------------
90 * |DMAC |SMAC |08|00|45|00|
91 * ----+-----------------+-----A---------------------
92 * skb->data
93 * skb->protocol = ntohs(ETH_P_IP)
94 * skb->vlan_proto = 0
95 * skb->vlan_tci = 0
96 * skb->vlan_present = 0
97 * l2_info->vlan_hdr_cnt = 0
98 * l2_info->protocol = ETH_P_IP
99 */
100static inline bool sfe_vlan_check_and_parse_tag(struct sk_buff *skb, struct sfe_l2_info *l2_info)
101{
102 struct vlan_hdr *vhdr;
103
Wayne Tanbb7f1782021-12-13 11:16:04 -0800104 while ((skb->protocol == htons(ETH_P_8021AD) || skb->protocol == htons(ETH_P_8021Q)) &&
105 l2_info->vlan_hdr_cnt < SFE_MAX_VLAN_DEPTH) {
106 if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) {
107 return false;
108 }
109 vhdr = (struct vlan_hdr *)skb->data;
110 l2_info->vlan_hdr[l2_info->vlan_hdr_cnt].tpid = skb->protocol;
111 l2_info->vlan_hdr[l2_info->vlan_hdr_cnt].tci = ntohs(vhdr->h_vlan_TCI);
112 skb->protocol = vhdr->h_vlan_encapsulated_proto;
113 l2_info->vlan_hdr_cnt++;
Nitin Shetty9af87d42022-02-11 16:25:29 +0530114 /*
115 * strip VLAN header
116 */
Wayne Tanbb7f1782021-12-13 11:16:04 -0800117 __skb_pull(skb, VLAN_HLEN);
Nitin Shetty9af87d42022-02-11 16:25:29 +0530118 skb_reset_network_header(skb);
Wayne Tanbb7f1782021-12-13 11:16:04 -0800119 }
120
121 l2_info->protocol = htons(skb->protocol);
122 return true;
123}
124
125/*
126 * sfe_vlan_undo_parse()
127 * Restore some skb fields which are modified when parsing VLAN tags.
128 */
129static inline void sfe_vlan_undo_parse(struct sk_buff *skb, struct sfe_l2_info *l2_info)
130{
131 if (l2_info->vlan_hdr_cnt == 0) {
132 return;
133 }
134
135 skb->protocol = l2_info->vlan_hdr[0].tpid;
136 __skb_push(skb, l2_info->vlan_hdr_cnt * VLAN_HLEN);
137}
138
139/*
140 * sfe_vlan_validate_ingress_tag()
141 * Validate ingress packet's VLAN tag
142 */
143static inline bool sfe_vlan_validate_ingress_tag(
144 struct sk_buff *skb, u8 count, struct sfe_vlan_hdr *vlan_hdr, struct sfe_l2_info *l2_info)
145{
146 u8 i;
147
148 if (likely(!sfe_is_l2_feature_enabled())) {
149 return true;
150 }
151
152 if (unlikely(count != l2_info->vlan_hdr_cnt)) {
153 return false;
154 }
155
156 for (i = 0; i < count; i++) {
157 if (unlikely(vlan_hdr[i].tpid != l2_info->vlan_hdr[i].tpid)) {
158 return false;
159 }
160
161 if (unlikely((vlan_hdr[i].tci & VLAN_VID_MASK) !=
162 (l2_info->vlan_hdr[i].tci & VLAN_VID_MASK))) {
163 return false;
164 }
165 }
166
167 return true;
168}
169
170/*
171 * sfe_vlan_add_tag()
172 * Add VLAN tags at skb->data.
173 * Normally, it is called just before adding 14-byte Ethernet header.
174 *
175 * This function does not update skb->mac_header so later code
176 * needs to call skb_reset_mac_header()/skb_reset_mac_len() to
177 * get correct skb->mac_header/skb->mac_len.
178 *
179 * It assumes:
180 * - skb->protocol is set
181 * - skb has enough headroom to write VLAN tags
182 * - 0 < count <= SFE_MAX_VLAN_DEPTH
183 *
184 * When entering (e.g. skb->protocol = ntohs(ETH_P_IP) or ntohs(ETH_P_PPP_SES)):
185 * -------------------------------+---------------------
186 * |45|00|...
187 * -------------------------------A---------------------
188 * skb->data
189 * -------------------------------v-----------------+-----+----------
190 * |11|00|xx|xx|xx|xx|00|21|45|00|...
191 * -------------------------------+-----------------+-----+----------
192 *
193 * When exiting (e.g. to add outer/inner tag = 88a80032/81000001):
194 * -------------+-----------+-----+---------------------
195 * |00|32|81|00|00|01|08|00|45|00|05|d8|....
196 * -------A-----+-----------+-----+---------------------
197 * skb->data
198 * -------v-----+-----------+-----+-----------------+-----+----------
199 * |00|32|81|00|00|01|88|64|11|00|xx|xx|xx|xx|00|21|45|00|
200 * -------------+-----------+-----+-----------------+-----+----------
201 * skb->protocol = ntohs(ETH_P_8021AD)
202 */
203static inline void sfe_vlan_add_tag(struct sk_buff *skb, int count, struct sfe_vlan_hdr *vlan)
204{
205 struct vlan_hdr *vhdr;
206 int i;
207 vlan += (count - 1);
208
209 for (i = 0; i < count; i++) {
Nitin Shetty9af87d42022-02-11 16:25:29 +0530210 vhdr = (struct vlan_hdr *)skb_push(skb, VLAN_HLEN);
Wayne Tanbb7f1782021-12-13 11:16:04 -0800211 vhdr->h_vlan_TCI = htons(vlan->tci);
212 vhdr->h_vlan_encapsulated_proto = skb->protocol;
213 skb->protocol = vlan->tpid;
214 vlan--;
215 }
216}
217
218#endif /* __SFE_VLAN_H */