blob: e7f6e4411efc9343c5564173fa6126fb4523713a [file] [log] [blame]
Yi Tsengbe342052017-11-03 10:21:23 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <core.p4>
18#include <v1model.p4>
19
20#include "../header.p4"
Yi Tsengbe342052017-11-03 10:21:23 -070021
Carmelo Casconeb5324e72018-11-25 02:26:32 -080022control Next (inout parsed_headers_t hdr,
23 inout fabric_metadata_t fabric_metadata,
24 inout standard_metadata_t standard_metadata) {
Yi Tsengbe342052017-11-03 10:21:23 -070025
Yi Tseng47eac892018-07-11 02:17:04 +080026 /*
27 * General actions.
28 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080029 @hidden
30 action output(port_num_t port_num) {
31 standard_metadata.egress_spec = port_num;
Yi Tseng20f9e7b2018-05-24 23:27:39 +080032 }
33
Carmelo Casconeb5324e72018-11-25 02:26:32 -080034 @hidden
Yi Tsengbe342052017-11-03 10:21:23 -070035 action rewrite_smac(mac_addr_t smac) {
36 hdr.ethernet.src_addr = smac;
37 }
38
Carmelo Casconeb5324e72018-11-25 02:26:32 -080039 @hidden
Yi Tsengbe342052017-11-03 10:21:23 -070040 action rewrite_dmac(mac_addr_t dmac) {
41 hdr.ethernet.dst_addr = dmac;
42 }
43
Carmelo Casconeb5324e72018-11-25 02:26:32 -080044 @hidden
45 action set_mpls_label(mpls_label_t label) {
46 fabric_metadata.mpls_label = label;
47 }
48
49 @hidden
50 action routing(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac) {
51 rewrite_smac(smac);
52 rewrite_dmac(dmac);
53 output(port_num);
54 }
55
56 @hidden
57 action mpls_routing(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac,
58 mpls_label_t label) {
59 set_mpls_label(label);
60 routing(port_num, smac, dmac);
Yi Tseng1b154bd2017-11-20 17:48:19 -080061 }
62
Yi Tseng47eac892018-07-11 02:17:04 +080063 /*
Carmelo Casconeb5324e72018-11-25 02:26:32 -080064 * Next VLAN table.
65 * Modify VLAN ID based on next ID.
Yi Tseng47eac892018-07-11 02:17:04 +080066 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080067 direct_counter(CounterType.packets_and_bytes) next_vlan_counter;
Yi Tseng1d842672017-11-28 16:06:52 -080068
Carmelo Casconeb5324e72018-11-25 02:26:32 -080069 action set_vlan(vlan_id_t vlan_id) {
70 fabric_metadata.vlan_id = vlan_id;
71 next_vlan_counter.count();
Yi Tseng1b154bd2017-11-20 17:48:19 -080072 }
73
Daniele Moro7c3a0022019-07-12 13:38:34 -070074#ifdef WITH_DOUBLE_VLAN_TERMINATION
75 action set_double_vlan(vlan_id_t outer_vlan_id, vlan_id_t inner_vlan_id) {
76 set_vlan(outer_vlan_id);
77 fabric_metadata.push_double_vlan = _TRUE;
78 fabric_metadata.inner_vlan_id = inner_vlan_id;
79 }
80#endif // WITH_DOUBLE_VLAN_TERMINATION
81
Carmelo Casconeb5324e72018-11-25 02:26:32 -080082 table next_vlan {
Yi Tseng20f9e7b2018-05-24 23:27:39 +080083 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080084 fabric_metadata.next_id: exact @name("next_id");
Yi Tseng20f9e7b2018-05-24 23:27:39 +080085 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +080086 actions = {
87 set_vlan;
Daniele Moro7c3a0022019-07-12 13:38:34 -070088#ifdef WITH_DOUBLE_VLAN_TERMINATION
89 set_double_vlan;
90#endif // WITH_DOUBLE_VLAN_TERMINATION
Yi Tseng47eac892018-07-11 02:17:04 +080091 @defaultonly nop;
Yi Tseng20f9e7b2018-05-24 23:27:39 +080092 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080093 const default_action = nop();
94 counters = next_vlan_counter;
Carmelo Cascone70e816b2019-03-19 16:15:47 -070095 size = NEXT_VLAN_TABLE_SIZE;
Yi Tseng20f9e7b2018-05-24 23:27:39 +080096 }
97
Carmelo Casconeb5324e72018-11-25 02:26:32 -080098#ifdef WITH_XCONNECT
99 /*
100 * Cross-connect table.
101 * Bidirectional forwarding for the same next id.
102 */
103 direct_counter(CounterType.packets_and_bytes) xconnect_counter;
104
105 action output_xconnect(port_num_t port_num) {
106 output(port_num);
Daniele Moro7c3a0022019-07-12 13:38:34 -0700107 fabric_metadata.last_eth_type = ETHERTYPE_VLAN;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800108 xconnect_counter.count();
109 }
110
111 action set_next_id_xconnect(next_id_t next_id) {
112 fabric_metadata.next_id = next_id;
113 xconnect_counter.count();
114 }
115
116 table xconnect {
117 key = {
118 standard_metadata.ingress_port: exact @name("ig_port");
119 fabric_metadata.next_id: exact @name("next_id");
120 }
121 actions = {
122 output_xconnect;
123 set_next_id_xconnect;
124 @defaultonly nop;
125 }
126 counters = xconnect_counter;
127 const default_action = nop();
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700128 size = XCONNECT_NEXT_TABLE_SIZE;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800129 }
130#endif // WITH_XCONNECT
131
132#ifdef WITH_SIMPLE_NEXT
Yi Tseng47eac892018-07-11 02:17:04 +0800133 /*
134 * Simple Table.
135 * Do a single egress action based on next id.
136 */
137 direct_counter(CounterType.packets_and_bytes) simple_counter;
138
139 action output_simple(port_num_t port_num) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800140 output(port_num);
Yi Tseng47eac892018-07-11 02:17:04 +0800141 simple_counter.count();
142 }
143
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800144 action routing_simple(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac) {
145 routing(port_num, smac, dmac);
146 simple_counter.count();
Yi Tseng47eac892018-07-11 02:17:04 +0800147 }
148
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800149 action mpls_routing_simple(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac,
150 mpls_label_t label) {
151 mpls_routing(port_num, smac, dmac, label);
152 simple_counter.count();
Yi Tseng47eac892018-07-11 02:17:04 +0800153 }
154
Yi Tsengbe342052017-11-03 10:21:23 -0700155 table simple {
156 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800157 fabric_metadata.next_id: exact @name("next_id");
Yi Tsengbe342052017-11-03 10:21:23 -0700158 }
Yi Tsengbe342052017-11-03 10:21:23 -0700159 actions = {
Yi Tseng47eac892018-07-11 02:17:04 +0800160 output_simple;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800161 routing_simple;
162 mpls_routing_simple;
163 @defaultonly nop;
Yi Tsengbe342052017-11-03 10:21:23 -0700164 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800165 const default_action = nop();
Yi Tseng3a5731e2018-01-22 11:38:58 -0800166 counters = simple_counter;
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700167 size = SIMPLE_NEXT_TABLE_SIZE;
Yi Tsengbe342052017-11-03 10:21:23 -0700168 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800169#endif // WITH_SIMPLE_NEXT
Yi Tsengbe342052017-11-03 10:21:23 -0700170
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800171#ifdef WITH_HASHED_NEXT
Yi Tseng47eac892018-07-11 02:17:04 +0800172 /*
173 * Hashed table.
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800174 * Execute an action profile selector based on next id.
Yi Tseng47eac892018-07-11 02:17:04 +0800175 */
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700176 @max_group_size(HASHED_SELECTOR_MAX_GROUP_SIZE)
177 action_selector(HashAlgorithm.crc16, HASHED_ACT_PROFILE_SIZE, 32w16) hashed_selector;
Yi Tseng47eac892018-07-11 02:17:04 +0800178 direct_counter(CounterType.packets_and_bytes) hashed_counter;
179
180 action output_hashed(port_num_t port_num) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800181 output(port_num);
Yi Tseng47eac892018-07-11 02:17:04 +0800182 hashed_counter.count();
183 }
184
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800185 action routing_hashed(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac) {
186 routing(port_num, smac, dmac);
187 hashed_counter.count();
Yi Tseng47eac892018-07-11 02:17:04 +0800188 }
189
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800190 action mpls_routing_hashed(port_num_t port_num, mac_addr_t smac, mac_addr_t dmac,
191 mpls_label_t label) {
192 mpls_routing(port_num, smac, dmac, label);
193 hashed_counter.count();
Yi Tseng47eac892018-07-11 02:17:04 +0800194 }
195
Yi Tsengbe342052017-11-03 10:21:23 -0700196 table hashed {
197 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800198 fabric_metadata.next_id: exact @name("next_id");
Yi Tseng3d3956d2018-01-31 17:28:05 -0800199 hdr.ipv4.dst_addr: selector;
200 hdr.ipv4.src_addr: selector;
Yi Tseng1d842672017-11-28 16:06:52 -0800201 fabric_metadata.ip_proto: selector;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800202 fabric_metadata.l4_sport: selector;
203 fabric_metadata.l4_dport: selector;
Yi Tsengbe342052017-11-03 10:21:23 -0700204 }
Yi Tsengbe342052017-11-03 10:21:23 -0700205 actions = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800206 output_hashed;
207 routing_hashed;
208 mpls_routing_hashed;
209 @defaultonly nop;
Yi Tsengbe342052017-11-03 10:21:23 -0700210 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800211 implementation = hashed_selector;
Yi Tseng3a5731e2018-01-22 11:38:58 -0800212 counters = hashed_counter;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800213 const default_action = nop();
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700214 size = HASHED_NEXT_TABLE_SIZE;
Yi Tsengbe342052017-11-03 10:21:23 -0700215 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800216#endif // WITH_HASHED_NEXT
Yi Tsengbe342052017-11-03 10:21:23 -0700217
218 /*
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800219 * Multicast
220 * Maps next IDs to PRE multicat group IDs.
Yi Tsengbe342052017-11-03 10:21:23 -0700221 */
Yi Tseng47eac892018-07-11 02:17:04 +0800222 direct_counter(CounterType.packets_and_bytes) multicast_counter;
223
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800224 action set_mcast_group_id(mcast_group_id_t group_id) {
225 standard_metadata.mcast_grp = group_id;
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200226 fabric_metadata.is_multicast = _TRUE;
Yi Tseng47eac892018-07-11 02:17:04 +0800227 multicast_counter.count();
Carmelo Casconea1061402018-02-03 17:39:59 -0800228 }
229
Carmelo Casconea1061402018-02-03 17:39:59 -0800230 table multicast {
Yi Tsengbe342052017-11-03 10:21:23 -0700231 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800232 fabric_metadata.next_id: exact @name("next_id");
Yi Tsengbe342052017-11-03 10:21:23 -0700233 }
234 actions = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800235 set_mcast_group_id;
236 @defaultonly nop;
Yi Tsengbe342052017-11-03 10:21:23 -0700237 }
Carmelo Casconea1061402018-02-03 17:39:59 -0800238 counters = multicast_counter;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800239 const default_action = nop();
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700240 size = MULTICAST_NEXT_TABLE_SIZE;
Yi Tsengbe342052017-11-03 10:21:23 -0700241 }
242
243 apply {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800244#ifdef WITH_XCONNECT
245 // xconnect might set a new next_id.
246 xconnect.apply();
247#endif // WITH_XCONNECT
248#ifdef WITH_SIMPLE_NEXT
249 simple.apply();
250#endif // WITH_SIMPLE_NEXT
251#ifdef WITH_HASHED_NEXT
252 hashed.apply();
253#endif // WITH_HASHED_NEXT
254 multicast.apply();
255 next_vlan.apply();
Yi Tsengbe342052017-11-03 10:21:23 -0700256 }
257}
258
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800259control EgressNextControl (inout parsed_headers_t hdr,
260 inout fabric_metadata_t fabric_metadata,
261 inout standard_metadata_t standard_metadata) {
262 @hidden
263 action pop_mpls_if_present() {
264 hdr.mpls.setInvalid();
265 // Assuming there's an IP header after the MPLS one.
Daniele Moro7c3a0022019-07-12 13:38:34 -0700266 fabric_metadata.last_eth_type = fabric_metadata.ip_eth_type;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800267 }
268
269 @hidden
270 action set_mpls() {
271 hdr.mpls.setValid();
272 hdr.mpls.label = fabric_metadata.mpls_label;
273 hdr.mpls.tc = 3w0;
274 hdr.mpls.bos = 1w1; // BOS = TRUE
275 hdr.mpls.ttl = fabric_metadata.mpls_ttl; // Decrement after push.
Daniele Moro7c3a0022019-07-12 13:38:34 -0700276 fabric_metadata.last_eth_type = ETHERTYPE_MPLS;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800277 }
278
279 @hidden
280 action push_vlan() {
281 // If VLAN is already valid, we overwrite it with a potentially new VLAN
282 // ID, and same CFI, PRI, and eth_type values found in ingress.
283 hdr.vlan_tag.setValid();
284 hdr.vlan_tag.cfi = fabric_metadata.vlan_cfi;
285 hdr.vlan_tag.pri = fabric_metadata.vlan_pri;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700286 hdr.vlan_tag.eth_type = fabric_metadata.last_eth_type;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800287 hdr.vlan_tag.vlan_id = fabric_metadata.vlan_id;
288 hdr.ethernet.eth_type = ETHERTYPE_VLAN;
289 }
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800290
Daniele Moro7c3a0022019-07-12 13:38:34 -0700291#ifdef WITH_DOUBLE_VLAN_TERMINATION
292 @hidden
293 action push_inner_vlan() {
294 // Then push inner VLAN TAG, rewriting correclty the outer vlan eth_type
295 // and the ethernet eth_type
296 hdr.inner_vlan_tag.setValid();
297 hdr.inner_vlan_tag.cfi = fabric_metadata.inner_vlan_cfi;
298 hdr.inner_vlan_tag.pri = fabric_metadata.inner_vlan_pri;
299 hdr.inner_vlan_tag.vlan_id = fabric_metadata.inner_vlan_id;
300 hdr.inner_vlan_tag.eth_type = fabric_metadata.last_eth_type;
301 hdr.vlan_tag.eth_type = ETHERTYPE_VLAN;
Daniele Moro77654f92019-07-30 10:29:54 -0700302 hdr.ethernet.eth_type = ETHERTYPE_QINQ;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700303 }
304#endif // WITH_DOUBLE_VLAN_TERMINATION
305
Yi Tseng47eac892018-07-11 02:17:04 +0800306 /*
307 * Egress VLAN Table.
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800308 * Pops the VLAN tag if the pair egress port and VLAN ID is matched.
Yi Tseng47eac892018-07-11 02:17:04 +0800309 */
310 direct_counter(CounterType.packets_and_bytes) egress_vlan_counter;
311
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800312 action pop_vlan() {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700313 hdr.ethernet.eth_type = fabric_metadata.last_eth_type;
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800314 hdr.vlan_tag.setInvalid();
Yi Tseng47eac892018-07-11 02:17:04 +0800315 egress_vlan_counter.count();
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800316 }
317
318 table egress_vlan {
319 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800320 fabric_metadata.vlan_id: exact @name("vlan_id");
321 standard_metadata.egress_port: exact @name("eg_port");
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800322 }
323 actions = {
324 pop_vlan;
Yi Tseng47eac892018-07-11 02:17:04 +0800325 @defaultonly nop;
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800326 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800327 const default_action = nop();
Yi Tseng47eac892018-07-11 02:17:04 +0800328 counters = egress_vlan_counter;
Carmelo Cascone70e816b2019-03-19 16:15:47 -0700329 size = EGRESS_VLAN_TABLE_SIZE;
Yi Tseng20f9e7b2018-05-24 23:27:39 +0800330 }
Yi Tsengbe342052017-11-03 10:21:23 -0700331
332 apply {
Carmelo Cascone1e8843f2018-07-19 19:01:12 +0200333 if (fabric_metadata.is_multicast == _TRUE
Carmelo Casconea5400af2018-07-17 22:11:54 +0200334 && standard_metadata.ingress_port == standard_metadata.egress_port) {
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700335 mark_to_drop(standard_metadata);
Carmelo Casconea5400af2018-07-17 22:11:54 +0200336 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800337
338 if (fabric_metadata.mpls_label == 0) {
339 if (hdr.mpls.isValid()) pop_mpls_if_present();
340 } else {
341 set_mpls();
342 }
343
Daniele Moro7c3a0022019-07-12 13:38:34 -0700344#ifdef WITH_DOUBLE_VLAN_TERMINATION
345 if (fabric_metadata.push_double_vlan == _TRUE) {
346 // Double VLAN termination.
347 push_vlan();
348 push_inner_vlan();
349 } else {
350 // If no push double vlan, inner_vlan_tag must be popped
351 hdr.inner_vlan_tag.setInvalid();
352#endif // WITH_DOUBLE_VLAN_TERMINATION
353 // Port-based VLAN tagging (by default all
354 // ports are assumed tagged)
355 if (!egress_vlan.apply().hit) {
356 // Push VLAN tag if not the default one.
357 if (fabric_metadata.vlan_id != DEFAULT_VLAN_ID) {
358 push_vlan();
359 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800360 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700361#ifdef WITH_DOUBLE_VLAN_TERMINATION
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800362 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700363#endif // WITH_DOUBLE_VLAN_TERMINATION
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800364
365 // TTL decrement and check.
366 if (hdr.mpls.isValid()) {
367 hdr.mpls.ttl = hdr.mpls.ttl - 1;
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700368 if (hdr.mpls.ttl == 0) mark_to_drop(standard_metadata);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800369 } else {
370 if(hdr.ipv4.isValid()) {
371 hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700372 if (hdr.ipv4.ttl == 0) mark_to_drop(standard_metadata);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800373 }
374#ifdef WITH_IPV6
375 else if (hdr.ipv6.isValid()) {
376 hdr.ipv6.hop_limit = hdr.ipv6.hop_limit - 1;
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700377 if (hdr.ipv6.hop_limit == 0) mark_to_drop(standard_metadata);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800378 }
379#endif // WITH_IPV6
380 }
Yi Tsengbe342052017-11-03 10:21:23 -0700381 }
382}