blob: 505b24b77b82e0204ca715bda547e865265dfe6a [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
104 l2_info->vlan_hdr_cnt = 0;
105
106 while ((skb->protocol == htons(ETH_P_8021AD) || skb->protocol == htons(ETH_P_8021Q)) &&
107 l2_info->vlan_hdr_cnt < SFE_MAX_VLAN_DEPTH) {
108 if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) {
109 return false;
110 }
111 vhdr = (struct vlan_hdr *)skb->data;
112 l2_info->vlan_hdr[l2_info->vlan_hdr_cnt].tpid = skb->protocol;
113 l2_info->vlan_hdr[l2_info->vlan_hdr_cnt].tci = ntohs(vhdr->h_vlan_TCI);
114 skb->protocol = vhdr->h_vlan_encapsulated_proto;
115 l2_info->vlan_hdr_cnt++;
116 __skb_pull(skb, VLAN_HLEN);
117 }
118
119 l2_info->protocol = htons(skb->protocol);
120 return true;
121}
122
123/*
124 * sfe_vlan_undo_parse()
125 * Restore some skb fields which are modified when parsing VLAN tags.
126 */
127static inline void sfe_vlan_undo_parse(struct sk_buff *skb, struct sfe_l2_info *l2_info)
128{
129 if (l2_info->vlan_hdr_cnt == 0) {
130 return;
131 }
132
133 skb->protocol = l2_info->vlan_hdr[0].tpid;
134 __skb_push(skb, l2_info->vlan_hdr_cnt * VLAN_HLEN);
135}
136
137/*
138 * sfe_vlan_validate_ingress_tag()
139 * Validate ingress packet's VLAN tag
140 */
141static inline bool sfe_vlan_validate_ingress_tag(
142 struct sk_buff *skb, u8 count, struct sfe_vlan_hdr *vlan_hdr, struct sfe_l2_info *l2_info)
143{
144 u8 i;
145
146 if (likely(!sfe_is_l2_feature_enabled())) {
147 return true;
148 }
149
150 if (unlikely(count != l2_info->vlan_hdr_cnt)) {
151 return false;
152 }
153
154 for (i = 0; i < count; i++) {
155 if (unlikely(vlan_hdr[i].tpid != l2_info->vlan_hdr[i].tpid)) {
156 return false;
157 }
158
159 if (unlikely((vlan_hdr[i].tci & VLAN_VID_MASK) !=
160 (l2_info->vlan_hdr[i].tci & VLAN_VID_MASK))) {
161 return false;
162 }
163 }
164
165 return true;
166}
167
168/*
169 * sfe_vlan_add_tag()
170 * Add VLAN tags at skb->data.
171 * Normally, it is called just before adding 14-byte Ethernet header.
172 *
173 * This function does not update skb->mac_header so later code
174 * needs to call skb_reset_mac_header()/skb_reset_mac_len() to
175 * get correct skb->mac_header/skb->mac_len.
176 *
177 * It assumes:
178 * - skb->protocol is set
179 * - skb has enough headroom to write VLAN tags
180 * - 0 < count <= SFE_MAX_VLAN_DEPTH
181 *
182 * When entering (e.g. skb->protocol = ntohs(ETH_P_IP) or ntohs(ETH_P_PPP_SES)):
183 * -------------------------------+---------------------
184 * |45|00|...
185 * -------------------------------A---------------------
186 * skb->data
187 * -------------------------------v-----------------+-----+----------
188 * |11|00|xx|xx|xx|xx|00|21|45|00|...
189 * -------------------------------+-----------------+-----+----------
190 *
191 * When exiting (e.g. to add outer/inner tag = 88a80032/81000001):
192 * -------------+-----------+-----+---------------------
193 * |00|32|81|00|00|01|08|00|45|00|05|d8|....
194 * -------A-----+-----------+-----+---------------------
195 * skb->data
196 * -------v-----+-----------+-----+-----------------+-----+----------
197 * |00|32|81|00|00|01|88|64|11|00|xx|xx|xx|xx|00|21|45|00|
198 * -------------+-----------+-----+-----------------+-----+----------
199 * skb->protocol = ntohs(ETH_P_8021AD)
200 */
201static inline void sfe_vlan_add_tag(struct sk_buff *skb, int count, struct sfe_vlan_hdr *vlan)
202{
203 struct vlan_hdr *vhdr;
204 int i;
205 vlan += (count - 1);
206
207 for (i = 0; i < count; i++) {
208 skb_push(skb, VLAN_HLEN);
209 vhdr = (struct vlan_hdr *)skb->data;
210 vhdr->h_vlan_TCI = htons(vlan->tci);
211 vhdr->h_vlan_encapsulated_proto = skb->protocol;
212 skb->protocol = vlan->tpid;
213 vlan--;
214 }
215}
216
217#endif /* __SFE_VLAN_H */