Daniele Moro | 08c9e7f | 2021-07-28 18:53:34 +0200 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2021-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 | #ifndef __SLICING__ |
| 18 | #define __SLICING__ |
| 19 | |
| 20 | // ACL-like classification, maps lookup metadata to slice_id and tc. For UE |
| 21 | // traffic, values can be overriden later by the SPGW PDR tables. |
| 22 | // To apply the same slicing and QoS treatment end-to-end, we use the IPv4 DSCP |
| 23 | // field to piggyback slice_id and tc (see EgressDscpRewriter). This is |
| 24 | // especially important for UE traffic, where classification based on PDRs can |
| 25 | // only happen at the ingress leaf switch (implementing the UPF function). |
| 26 | // As such, for traffic coming from selected ports, we allow trusting the |
| 27 | // slice_id and tc values carried in the dscp. |
| 28 | control IngressSliceTcClassifier (in parsed_headers_t hdr, |
| 29 | inout fabric_metadata_t fabric_md, |
| 30 | in standard_metadata_t standard_metadata) { |
| 31 | |
| 32 | direct_counter(CounterType.packets) classifier_stats; |
| 33 | |
| 34 | action set_slice_id_tc(slice_id_t slice_id, tc_t tc) { |
| 35 | fabric_md.slice_id = slice_id; |
| 36 | fabric_md.tc = tc; |
| 37 | classifier_stats.count(); |
| 38 | } |
| 39 | |
| 40 | // Should be used only for infrastructure ports (leaf-leaf, or leaf-spine), |
| 41 | // or ports facing servers that implement early classification based on the |
| 42 | // SDFAB DSCP encoding (slice_id++tc). |
| 43 | action trust_dscp() { |
| 44 | fabric_md.slice_id = hdr.ipv4.dscp[SLICE_ID_WIDTH+TC_WIDTH-1:TC_WIDTH]; |
| 45 | fabric_md.tc = hdr.ipv4.dscp[TC_WIDTH-1:0]; |
| 46 | classifier_stats.count(); |
| 47 | } |
| 48 | |
| 49 | table classifier { |
| 50 | key = { |
| 51 | standard_metadata.ingress_port : ternary @name("ig_port"); |
| 52 | fabric_md.lkp.ipv4_src : ternary @name("ipv4_src"); |
| 53 | fabric_md.lkp.ipv4_dst : ternary @name("ipv4_dst"); |
| 54 | fabric_md.lkp.ip_proto : ternary @name("ip_proto"); |
| 55 | fabric_md.lkp.l4_sport : ternary @name("l4_sport"); |
| 56 | fabric_md.lkp.l4_dport : ternary @name("l4_dport"); |
| 57 | } |
| 58 | actions = { |
| 59 | set_slice_id_tc; |
| 60 | trust_dscp; |
| 61 | } |
| 62 | const default_action = set_slice_id_tc(DEFAULT_SLICE_ID, DEFAULT_TC); |
| 63 | counters = classifier_stats; |
| 64 | size = QOS_CLASSIFIER_TABLE_SIZE; |
| 65 | } |
| 66 | |
| 67 | apply { |
| 68 | classifier.apply(); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // Provides metering and mapping to queues based on slice_id and tc. Should be |
| 73 | // applied after any other block writing slice_id and tc. |
| 74 | control IngressQos (inout fabric_metadata_t fabric_md, |
| 75 | inout standard_metadata_t standard_metadata) { |
| 76 | |
| 77 | // One meter per tc per slice. The index should be slice_id++tc. |
| 78 | meter(1 << SLICE_TC_WIDTH, MeterType.bytes) slice_tc_meter; |
| 79 | |
| 80 | direct_counter(CounterType.packets) queues_stats; |
| 81 | |
| 82 | action set_queue(qid_t qid) { |
| 83 | // We can't set the queue id in bmv2. |
| 84 | queues_stats.count(); |
| 85 | } |
| 86 | |
| 87 | // For policing. |
| 88 | action meter_drop() { |
| 89 | mark_to_drop(standard_metadata); |
| 90 | queues_stats.count(); |
| 91 | } |
| 92 | |
| 93 | table queues { |
| 94 | key = { |
| 95 | fabric_md.slice_id: exact @name("slice_id"); |
| 96 | fabric_md.tc: exact @name("tc"); |
| 97 | fabric_md.packet_color: ternary @name("color"); // 0=GREEN, 1=YELLOW, 2=RED |
| 98 | } |
| 99 | actions = { |
| 100 | set_queue; |
| 101 | meter_drop; |
| 102 | } |
| 103 | const default_action = set_queue(0); // 0 = Best Effort |
| 104 | counters = queues_stats; |
| 105 | // Two times the number of tcs for all slices, because we might need to |
| 106 | // match on different colors for the same slice and tc. |
| 107 | size = 1 << (SLICE_TC_WIDTH + 1); |
| 108 | } |
| 109 | |
| 110 | slice_tc_t slice_tc = fabric_md.slice_id++fabric_md.tc; |
| 111 | |
| 112 | apply { |
| 113 | // Meter index should be 0 for all packets with default slice_id and tc. |
| 114 | slice_tc_meter.execute_meter((bit<32>) slice_tc, fabric_md.packet_color); |
| 115 | fabric_md.dscp = slice_tc; |
| 116 | queues.apply(); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | // Allows per-egress port rewriting of the outermost IPv4 DSCP field to |
| 121 | // piggyback slice_id and tc across the fabric. |
| 122 | control EgressDscpRewriter (inout parsed_headers_t hdr, |
| 123 | in fabric_metadata_t fabric_md, |
| 124 | in standard_metadata_t standard_metadata) { |
| 125 | |
| 126 | bit<6> tmp_dscp = fabric_md.dscp; |
| 127 | |
| 128 | action rewrite() { |
| 129 | // Do nothing, tmp_dscp is already initialized. |
| 130 | } |
| 131 | |
| 132 | // Sets the DSCP field to zero. Should be used for edge ports facing devices |
| 133 | // that do not support the SDFAB DSCP encoding. |
| 134 | action clear() { |
| 135 | tmp_dscp = 0; |
| 136 | } |
| 137 | |
| 138 | table rewriter { |
| 139 | key = { |
| 140 | standard_metadata.egress_port : exact @name("eg_port"); |
| 141 | } |
| 142 | actions = { |
| 143 | rewrite; |
| 144 | clear; |
| 145 | @defaultonly nop; |
| 146 | } |
| 147 | const default_action = nop; |
| 148 | size = DSCP_REWRITER_TABLE_SIZE; |
| 149 | } |
| 150 | |
| 151 | apply { |
| 152 | if (rewriter.apply().hit) { |
| 153 | #ifdef WITH_SPGW |
| 154 | if (hdr.gtpu_ipv4.isValid()) { |
| 155 | hdr.ipv4.dscp = tmp_dscp; |
| 156 | } else |
| 157 | #endif // WITH_SPGW |
| 158 | if (hdr.ipv4.isValid()) { |
| 159 | hdr.inner_ipv4.dscp = tmp_dscp; |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | #endif |