├── LICENSE ├── README.md ├── dataset-simulation ├── dataset-processor-cicids2017.py └── dataset-processor-nb15.py ├── iisy ├── iisy.p4 ├── resource-model.py └── worst-case-feature-table.py ├── leo-generator ├── leo_ctrlplane_generator.py ├── leo_dataplane_generator.py ├── leo_sram.py ├── leo_tcam.py └── leo_templates.py └── leo ├── feature-budget-finder.py ├── leo-1m-flows.p4 ├── leo.p4 └── resource-model.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Usman Jafri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Leo: Online ML-based Traffic Classification at Multi-Terabit Line Rate 2 | 3 | Leo is an in-network traffic classification system that applies decision tree inference to every packet through a programmable switch. Leo supports a **class** of decision trees in a *run-time programmable* and *resource-efficient* manner while achieving multi-terabit line rate. 4 | 5 | This artifact accompanies the paper: *"Leo: Online ML-based Traffic Classification at Multi-Terabit Line Rate"*. Syed Usman Jafri, Sanjay Rao, Vishal Shrivastav and Mohit Tawarmalani. In Proceedings of the 21th USENIX Symposium on Networked Systems Design and Implementation, NSDI '24, Santa Clara, CA, US. 6 | 7 | If you use this artifact, please cite: 8 | ``` 9 | @inproceedings{leo_nsdi_2024, 10 | author = {Jafri, Syed Usman and Rao, Sanjay and Shrivastav, Vishal and Tawarmalani, Mohit}, 11 | title = {Leo: Online ML-based Traffic Classification at Multi-Terabit Line Rate}, 12 | year = {2024}, 13 | url = {TODO, 14 | doi = {TODO}, 15 | booktitle = {21th USENIX Symposium on Networked Systems Design and Implementation (NSDI 24)}, 16 | series = {NSDI '24} 17 | } 18 | ``` 19 | ## 1. Pre-requisites: 20 | 21 | ### 1A. Hardware: 22 | 23 | - Intel® Tofino™ Switch 24 | - Server (equipped with NIC) 25 | 26 | We use the **EdgeCore Wedge-100BF-32x** switch for our evaluation. 27 | 28 | ### 1B. Software: 29 | 30 | - Intel Barefoot SDK 9.11.1 31 | - Ubuntu 22.04 32 | - Python 3.10.12 33 | - scikit-learn 1.3.0 34 | - Scapy 2.5 35 | - pandas 2.0.3 36 | - GNU Make 4.3 37 | - matplotlib 3.7.2 38 | 39 | While using Ubuntu 22.04 as the operating system is not a hard requirement, it is what was used for all our evaluation. 40 | 41 | ## 2. Datasets 42 | 43 | The following two datasets for evaluating classifation accuracy of Leo and related work. 44 | 45 | - [UNSW-NB15](https://research.unsw.edu.au/projects/unsw-nb15-dataset) 46 | - [CICIDS-2017](https://www.unb.ca/cic/datasets/ids-2017.html) 47 | 48 | These datasets should be downloaded separately and placed in the `dataset-simulation` directory in the following hierarchy: 49 | 50 | ``` 51 | Leo/ 52 | |_ dataset-simulation/ 53 | |_ UNSW-NB15/ 54 | |_ Friday-WorkingHours-Afternoon-DDos.pcap_ISCX.csv 55 | |_ Friday-WorkingHours-Morning.pcap_ISCX.csv 56 | |_ ... 57 | |_ CICIDS-2017/ 58 | |_ UNSW-NB15_1.csv 59 | |_ UNSW-NB15_2.csv 60 | |_ ... 61 | |_ ... 62 | ``` 63 | 64 | ## 3. Leo parameters 65 | 66 | Leo generates a hardware mapping based on a set of parameters that identify a decision tree. The following parameters are available to the user: 67 | 68 | **SUB_TREE_SIZE** - The degree of flattening Leo applies at every layer. For example, `SUB_TREE_SIZE=2` flattens 2 levels (3 nodes) of the tree to the same layer. `SUB_TREE_SIZE=3` flattens 3 levels (7 nodes) and so on. 69 | 70 | **MEM_TYPE** - The type of memory to use for the boolean tables. Possible options: `SRAM` or `TCAM`. 71 | 72 | **DEPTH** - The maximum number of internal layers to implement. For example, `DEPTH=7` will produce 7 layers of internal nodes plus an additional layer of leaf nodes. 73 | 74 | **LEAVES** - A limit on the number of leaves on each level of the tree. Note: `LEAVES=0` will allow the tree to grow naturally with no leaf limit. 75 | 76 | **FEATURES** - The number of features the the tree should support. 77 | 78 | ## 4. Using Leo 79 | 80 | ### 4A. Setting up the data plane 81 | 82 | The following steps outline how to deploy Leo on real switch. 83 | 84 | 1. Identify the target Leo tree class you would like to support. The available parameters are explained in Section 3. 85 | 86 | 2. Clone the Leo repository on your switch. 87 | 88 | ``` 89 | git clone git@github.com:Purdue-ISL/Leo.git 90 | ``` 91 | 92 | 3. Open a console and navigate to Leo P4 generator sub-folder of the Leo repository. 93 | 94 | ``` 95 | cd Leo/leo-generator 96 | ``` 97 | 98 | 4. Run the Leo P4 generator, which is used as follows: 99 | 100 | ``` 101 | python3 leo_dataplane_generator.py [-h] (--sram | --tcam) --filename 102 | --sub_tree SUB_TREE_SIZE --depth DEPTH --features FEATURES 103 | [--leaf_limit LEAVES] [--transient] 104 | ``` 105 | 106 | For example, for a tree class using SRAM memory with maximum depth 10, 12 features and a sub-tree size of 2 invoke the following command: 107 | 108 | ``` 109 | python3 leo_dataplane_generator.py --sram --filename demo.p4 --sub_tree 2 --depth 10 110 | --features 12 111 | ``` 112 | 113 | To introduce a leaf limit of 500 leaves add the `--leaf_limit` flag as follows: 114 | 115 | ``` 116 | python3 leo_dataplane_generator.py --sram --filename demo.p4 --sub_tree 2 --depth 10 117 | --features 12 --leaf_limit 500 118 | ``` 119 | 120 | To enable support for handling transient states during runtime tree updates add the `--transient` flag. 121 | 122 | 5. Create a `build` folder. This folder will contain the compiled binary and other supporting files to run the switch. 123 | 124 | ``` 125 | mkdir build 126 | ``` 127 | 128 | 6. Setup the build directory. Make sure the `$SDE` and `$SDE_INSTALL` environment variables were setup during the Barefoot SDK installation. 129 | 130 | ``` 131 | cmake $SDE/p4studio -DCMAKE_INSTALL_PREFIX=$SDE_INSTALL -DCMAKE_MODULE_PATH=$SDE/cmake 132 | -DTOFINO=ON -DTOFINO2=OFF -DP4_LANG=p4_16 -DP4_NAME=Leo -DP4_PATH=$HOME/Leo/leo-generator/demo.p4 133 | ``` 134 | 135 | 7. Invoke the Tofino compiler to generate the switch binary: 136 | 137 | ``` 138 | sudo make 139 | sudo make install 140 | ``` 141 | 142 | 8. Finally, deploy the switch binary to the switch: 143 | 144 | ``` 145 | sudo -E $SDE/run_switchd.sh -p Leo 146 | ``` 147 | 148 | ### 4B. Setting up the control plane 149 | 150 | 1. Once the switch is up and running with Leo, enable the switch ports for trasmission. In this example, the ports `33/0` and `33/2` are enabled to allow forwarding packets to the switch CPU. The ports `2/-` and `4/-` are connected to the server. 151 | 152 | **Note:** the port numbers may vary based on how the cables between the switch and server were connected. 153 | 154 | ``` 155 | ucli 156 | port-add 33/0 10G NONE 157 | port-add 33/2 10G NONE 158 | port-add 2/- 100G NONE 159 | port-add 4/- 100G NONE 160 | port-enb 33/0 161 | port-enb 33/2 162 | port-enb 2/0 163 | port-enb 4/0 164 | exit 165 | ``` 166 | 167 | 2. Open a console and navigate to Leo P4 generator sub-folder of the Leo repository. 168 | 169 | ``` 170 | cd Leo/leo-generator 171 | ``` 172 | 173 | 3. Train the decision tree model using Python3's scikit-learn library. Make sure the `DEPTH` and `LEAVES` parameter are configured during training. 174 | 175 | - Please see the scikit-learn [documentation](https://scikit-learn.org/0.21/documentation.html) for usage instructions. 176 | 177 | - For the two datasets used for in our evaluation, we provide sample training scripts in the *dataset-simulation* folder. 178 | 179 | - In addition to the depth and leaves parameters, ensure that the number of features is set to `FEATURES`. We provide a function `select_features(...)` in the sample training scripts for this purpose. The function runs the Recursive Feature Elimination algorithm to identify the best subset of features for training. 180 | 181 | - Once the model is trained, use scikit-learn's `export_text(...)` function to export the trained model to a text file. 182 | 183 | 4. Invoke the Leo generator to generate control plane code. 184 | 185 | **Note:** Make sure that the `SUB_TREE_SIZE` and `DEPTH` parameters match those used earlier for generating the data plane in *Section 4a (4)*. 186 | 187 | ``` 188 | python3 leo_ctrlplane_generator.py [-h] (--sram | --tcam) --output_filename 189 | --sub_tree SUB_TREE_SIZE --depth DEPTH --input_filename [--transient] 190 | ``` 191 | 192 | 5. Switch into the Python Barefoot control plane and execute the generated Leo control plane code. 193 | 194 | Copy the the control plane code from the previous step (`--output_filename`) into the following block of code: 195 | 196 | ``` 197 | bfrt_python 198 | cmds='''''' 199 | exec(cmds) 200 | ``` 201 | 202 | **Note on feature extraction:** 203 | 204 | The Leo generator also produces a text file *feature_mapping.txt* that lists which Leo feature header should be populated with which feature from the dataset. 205 | 206 | **Example feature mapping for CICIDS-2017:** 207 | ``` 208 | hdr.leo.feature_1 = SYNFlagCount 209 | hdr.leo.feature_2 = MinPacketLength 210 | hdr.leo.feature_3 = DestinationPort 211 | ... 212 | ``` 213 | 214 | The user will have to provide P4 code to extract features from the packet (or stateful features from registers). This is not done automatically, since feature extraction logic is dependant on the type of feature itself. 215 | 216 | Look for the following markers in the generated P4 code: 217 | 218 | - `// Declare stateful features registers here` 219 | - `// Execute stateful features registers here` 220 | - `// Populate features to hdr.leo.feature_i here` 221 | 222 | To see an example what feature extraction code may look like, please see *Leo/leo-1m-flows.p4*. This is a TCAM implementation that supports 1 million flows using 4 stateful and 1 stateless feature in a TCAM-based 10-depth tree. 223 | 224 | ## 5. Using the resource models 225 | 226 | ### 5A. Leo 227 | 228 | The Leo resource model calculates the number of table entries required for a target decision tree class. The model implements the analysis presented in Section 6 of the paper. 229 | 230 | **Usage:** 231 | 232 | ``` 233 | python3 resource-model.py [-h] (--sram | --tcam) [--transient] 234 | --muxed_alu_config MUXED_ALU_CONFIG 235 | ``` 236 | 237 | - `MUXED_ALU_CONFIG` represents a comma-separated list of the number of Muxed ALUs in a switch stage. For example, `7,3,3,1` means: 7 Muxed ALUs (3 tree levels) in the first stage, 3 Muxed ALUs (2 tree levels) in the second and third stages and 1 Muxed ALU (1 tree level) in the fourth stage. 238 | - Only one of `--sram` or `--tcam` can be supplied. This controls whether to calculate memory requirements for Leo-SRAM or Leo-TCAM. 239 | - Include the `--transient` argument to include the additional overhead when accounting for transient state handling for runtime tree updates. 240 | 241 | Note that an additional layer for the leaf layer is added automatically. 242 | 243 | ### 5B. IIsy 244 | 245 | The IIsy resource model calculates the total number of table entries required and implements the analysis presented in Section 3 - Propositions 1 and 2, Appendix A.1 and A.2 of the paper. 246 | 247 | **Usage - Proposition 1 (SRAM):** 248 | 249 | ``` 250 | python3 resource-model.py p1 [-h] --n N --d D --k K 251 | ``` 252 | - `N` is the number of features 253 | - `D` is the depth of the tree (excluding leaf layer). 254 | - `K` is the maximum feature value. 255 | 256 | **Usage - Proposition 2 (TCAM):** 257 | 258 | ``` 259 | python3 resource-model.py p2 [-h] --filename FILENAME --N_max N_MAX --K_power_max K_POWER_MAX 260 | ``` 261 | 262 | With the `p2` argument, the resource model produces a CSV file containing the resource required for the proposition 2 family of trees using a variety of `N`, `K` combinations. 263 | 264 | - `N_MAX` is the maximum number of features to explore up to. For example, `--N_max 5` will explore N=2, 3, 4, 5. 265 | - `K_POWER_MAX` is the maximum feature value K to explore up to. Represented as a power of 2. For example, `--K_power_max 4` will explore K=3, 7, 15. 266 | 267 | **Usage - TCAM feature table:** 268 | 269 | ``` 270 | python3 worst-case-feature-table.py [-h] --width WIDTH --upper_lim UPPER_LIM --leaves LEAVES 271 | ``` 272 | 273 | - `WIDTH` is the width of the features (in number of bits). 274 | - `UPPER_LIM` is the maximum value a feature can take. 275 | - `LEAVES` is the number of leaf nodes in the tree class. 276 | 277 | ## 6. License 278 | 279 | The P4 code in this repository makes use of Tofino externs/includes which can be openly published under [Open-Tofino](https://github.com/barefootnetworks/Open-Tofino). Note that you will still need to obtain a license to use the Intel Barefoot SDK to compile the P4 code. 280 | 281 | ## 7. Contact 282 | Please contact ```jafri3@purdue.edu``` for any questions. -------------------------------------------------------------------------------- /dataset-simulation/dataset-processor-cicids2017.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import csv 4 | import itertools 5 | import numpy as np 6 | import pandas as pd 7 | import matplotlib.pyplot as plt 8 | from subprocess import call 9 | from sklearn.preprocessing import LabelEncoder 10 | from sklearn.tree import DecisionTreeClassifier, export_graphviz, export_text 11 | from sklearn.model_selection import train_test_split 12 | from sklearn.metrics import confusion_matrix, f1_score 13 | from sklearn.preprocessing import LabelEncoder 14 | from sklearn.inspection import permutation_importance 15 | from sklearn.feature_selection import RFE 16 | from statistics import median, mean 17 | 18 | def read_and_clean_dataset(folder): 19 | filenames = [ 20 | 'Monday-WorkingHours.pcap_ISCX.csv', 21 | 'Tuesday-WorkingHours.pcap_ISCX.csv', 22 | 'Wednesday-workingHours.pcap_ISCX.csv', 23 | 'Thursday-WorkingHours-Morning-WebAttacks.pcap_ISCX.csv', 24 | 'Thursday-WorkingHours-Afternoon-Infilteration.pcap_ISCX.csv', 25 | 'Friday-WorkingHours-Afternoon-DDos.pcap_ISCX.csv', 26 | 'Friday-WorkingHours-Afternoon-PortScan.pcap_ISCX.csv', 27 | 'Friday-WorkingHours-Morning.pcap_ISCX.csv', 28 | ] 29 | 30 | dataset = [] 31 | for filename in filenames: 32 | dataset.append(pd.read_csv(os.path.join(folder, filename))) 33 | 34 | dataset = pd.concat(dataset) 35 | 36 | # Removing space from labels 37 | column_names = [] 38 | for col in dataset.columns: 39 | new_column_name = col.replace(' ', '') 40 | column_names.append(new_column_name) 41 | 42 | dataset.columns = column_names 43 | 44 | # Removing non-alphabetic characters and cleaning up double-spaces 45 | old_labels = dataset['Label'].unique() 46 | new_labels = [] 47 | for label in old_labels: 48 | new_label = re.sub('[^a-zA-Z ]+', '', label) 49 | new_label = re.sub('\s', '_', new_label) 50 | new_label = new_label.replace('__', '_') 51 | new_labels.append(new_label) 52 | 53 | for i in range(len(new_labels)): 54 | dataset['Label'] = dataset['Label'].replace({old_labels[i] : new_labels[i]}) 55 | 56 | # Removing rows with missing data and rows with infinite data 57 | dataset = dataset.replace([np.inf, -np.inf], np.nan) 58 | dataset = dataset.dropna() 59 | return dataset 60 | 61 | def preprocess_dataset(dataset, use_switch_features, bin_threshold): 62 | # Keeping some columns only 63 | if use_switch_features: 64 | dataset = dataset.loc[:, dataset.columns.intersection(['DestinationPort', 'FlowDuration', 'TotalFwdPackets', 'TotalBackwardPackets', 'TotalLengthofFwdPackets', 'TotalLengthofBwdPackets', 'FwdPacketLengthMax', 'FwdPacketLengthMin', 'BwdPacketLengthMax', 'BwdPacketLengthMin', 'FlowIATMax', 'FlowIATMin', 'FwdIATTotal', 'FwdIATMax', 'FwdIATMin', 'BwdIATTotal', 'BwdIATMax', 'BwdIATMin', 'FwdPSHFlags', 'BwdPSHFlags', 'FwdURGFlags', 'BwdURGFlags', 'FwdHeaderLength', 'BwdHeaderLength', 'MinPacketLength', 'MaxPacketLength', 'FINFlagCount', 'SYNFlagCount', 'RSTFlagCount', 'PSHFlagCount', 'ACKFlagCount', 'URGFlagCount', 'CWEFlagCount', 'ECEFlagCount', 'Init_Win_bytes_forward', 'Init_Win_bytes_backward', 'act_data_pkt_fwd', 'min_seg_size_forward', 'ActiveMax', 'ActiveMin', 'IdleMax', 'IdleMin', 'Label'])] 65 | 66 | if bin_threshold == -1: 67 | dataset.loc[dataset.Label == 'BENIGN', 'Label'] = 'BENIGN' 68 | dataset.loc[dataset.Label != 'BENIGN', 'Label'] = 'MALICIOUS' 69 | else: 70 | counts = dataset.Label.value_counts() 71 | low_count_classes = counts[counts < bin_threshold] 72 | low_count_classes = low_count_classes.index.ravel() 73 | for c in low_count_classes: 74 | dataset.loc[dataset.Label == c, 'Label'] = 'OtherMalicious' 75 | 76 | return dataset 77 | 78 | def plot_feature_importance_mdi(model, features, filename): 79 | importances = pd.DataFrame({'feature' : features, 'importance' : model.feature_importances_}) 80 | importances = importances.sort_values('importance', ascending=False).set_index('feature') 81 | plt.rcParams['figure.figsize'] = (15, 5) 82 | fig, ax = plt.subplots() 83 | importances.plot.bar(ax=ax) 84 | ax.set_title("Feature importances using MDI") 85 | ax.set_ylabel("Mean decrease in impurity") 86 | fig.tight_layout() 87 | plt.savefig(filename + 'mdi.pdf', bbox_inches='tight') 88 | plt.close() 89 | 90 | def plot_permutation_importance(model, X_test, y_test, features, filename): 91 | result = permutation_importance(model, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2) 92 | importances = pd.DataFrame({'feature':features, 'importance' : result.importances_mean}) 93 | importances = importances.sort_values('importance', ascending=False).set_index('feature') 94 | plt.rcParams['figure.figsize'] = (10, 5) 95 | fig, ax = plt.subplots() 96 | importances.plot.bar(ax=ax) 97 | ax.set_title("Feature importances using permutation on full model") 98 | ax.set_ylabel("Mean accuracy decrease") 99 | fig.tight_layout() 100 | plt.savefig(filename + 'permutation.pdf', bbox_inches='tight') 101 | plt.close() 102 | 103 | def select_features(num_features, model, x, y, features): 104 | rfe = RFE(model, n_features_to_select=num_features) 105 | rfe.fit(x, y) 106 | feature_map = [(i, v) for i, v in itertools.zip_longest(rfe.get_support(), features)] 107 | map = [i[0] for i in feature_map] 108 | features = [] 109 | for i in feature_map: 110 | if i[0]: 111 | features.append(i[1]) 112 | 113 | return map, features 114 | 115 | def main(): 116 | os.mkdir('results') 117 | 118 | experiments = [(8, 256, 3, True, 6000), (7, 128, 4, True, 6000), (6, 64, 6, True, 6000), (5, 32, 10, True, 6000), (4, 16, 14, True, 6000), (14, 16384, 2, True, 6000), (13, 8192, 4, True, 6000), (12, 4096, 5, True, 6000), (11, 2096, 8, True, 6000), (10, 1024, 14, True, 6000)] 119 | 120 | boxs = [] 121 | results = [] 122 | for exp in experiments: 123 | # Training random forest tree 124 | filename = 'D' + str(exp[0]) + '-L' + str(exp[1]) + '-F' + str(exp[2]) + '-SWITCHFEATURES' + str(exp[3]) 125 | print(filename) 126 | 127 | dataset = read_and_clean_dataset('CICIDS2017') 128 | dataset = preprocess_dataset(dataset, exp[3], exp[4]) 129 | 130 | print('Shape:', dataset.shape) 131 | print(dataset.Label.value_counts()) 132 | num_classes = len(dataset.Label.unique()) 133 | features = dataset.columns.tolist()[:-1] 134 | 135 | # Encoding labels 136 | labelencoder = LabelEncoder() 137 | y = labelencoder.fit_transform(dataset.Label) 138 | dataset = dataset.drop(['Label'], axis=1).values 139 | 140 | # Splitting up train and test sets 141 | X_train, X_test, y_train, y_test = train_test_split(dataset, y, train_size = 0.75, test_size = 0.25, stratify = y) 142 | 143 | model = DecisionTreeClassifier(max_depth=exp[0], max_leaf_nodes=exp[1], criterion='entropy', class_weight='balanced') 144 | 145 | map, features = select_features(exp[2], model, X_train, y_train, features) 146 | X_train = pd.DataFrame(X_train) 147 | X_test = pd.DataFrame(X_test) 148 | X_train = X_train.iloc[:, map] 149 | X_test = X_test.iloc[:, map] 150 | 151 | model.fit(X_train, y_train) 152 | 153 | # plot_feature_importance_mdi(model, features, filename) 154 | # plot_permutation_importance(model, X_test, y_test, features, filename) 155 | 156 | 157 | y_predict = model.predict(X_test) 158 | y_train_predict = model.predict(X_train) 159 | cm_test = confusion_matrix(y_test, y_predict) 160 | cm_train = confusion_matrix(y_train, y_train_predict) 161 | cm_test = cm_test.tolist() 162 | cm_train = cm_train.tolist() 163 | 164 | class_f1 = f1_score(y_test, y_predict, average=None) 165 | macro_f1 = f1_score(y_test, y_predict, average='macro') 166 | results.append(class_f1) 167 | boxs.append({ 168 | 'label' : 'Depth ' + str(exp[0]) + '\nLeaves ' + str(exp[1]) + '\nFeatures ' + str(exp[2]), 169 | 'whislo': min(class_f1), 170 | 'q1' : min(class_f1), 171 | 'med' : median(class_f1), 172 | 'q3' : max(class_f1), 173 | 'whishi': max(class_f1), 174 | 'mean' : mean(class_f1), 175 | 'fliers': [] 176 | }) 177 | print('Test set - Macro F1', macro_f1) 178 | 179 | lab = labelencoder.inverse_transform([x for x in range(num_classes)]) 180 | lab = lab.tolist() 181 | for i in range(len(cm_test)): 182 | cm_test[i].insert(0, 'Actual-' + lab[i]) 183 | cm_train[i].insert(0, 'Actual-' + lab[i]) 184 | 185 | lab.insert(0, 'Predicted-->') 186 | 187 | with open('results/results.csv', 'a') as my_csv: 188 | csvWriter = csv.writer(my_csv, delimiter=',') 189 | csvWriter.writerow([filename]) 190 | csvWriter.writerow([len(features)] + features) 191 | csvWriter.writerow(lab) 192 | csvWriter.writerows(cm_test) 193 | csvWriter.writerow(['F1 score'] + class_f1.tolist() + [macro_f1]) 194 | csvWriter.writerow(lab) 195 | csvWriter.writerows(cm_train) 196 | csvWriter.writerow(['=========================================']) 197 | 198 | out_filename = 'results/' + os.path.split(filename)[-1].split('.')[0] 199 | dot_filename = out_filename + '.dot' 200 | export_graphviz(model, out_file=dot_filename, class_names=labelencoder.inverse_transform([x for x in range(num_classes)]), feature_names=features, proportion = True) 201 | call(['dot', '-Tpdf', dot_filename, '-o', out_filename + '.pdf']) 202 | call(['rm', dot_filename]) 203 | with open('results/results.txt', 'a') as my_txt: 204 | my_txt.write(filename + '\n') 205 | my_txt.write(export_text(model, feature_names=features)) 206 | my_txt.write('=========================================\n') 207 | 208 | fig, ax = plt.subplots() 209 | ax.bxp(boxs, showfliers=False, showcaps=False, showmeans=True) 210 | ax.set_ylabel('F1 score') 211 | plt.savefig('results/cicids2017-box-plot.pdf', bbox_inches='tight') 212 | plt.close() 213 | 214 | if __name__ == '__main__': 215 | main() -------------------------------------------------------------------------------- /dataset-simulation/dataset-processor-nb15.py: -------------------------------------------------------------------------------- 1 | import os 2 | import csv 3 | import itertools 4 | import numpy as np 5 | import pandas as pd 6 | import matplotlib.pyplot as plt 7 | from subprocess import call 8 | from sklearn.preprocessing import LabelEncoder 9 | from sklearn.tree import DecisionTreeClassifier, export_graphviz, export_text 10 | from sklearn.model_selection import train_test_split 11 | from sklearn.metrics import confusion_matrix, f1_score 12 | from sklearn.preprocessing import LabelEncoder 13 | from sklearn.inspection import permutation_importance 14 | from sklearn.feature_selection import RFE 15 | from statistics import median, mean 16 | 17 | def read_and_clean_dataset(folder): 18 | filenames = [ 19 | 'UNSW_NB15_training-set.csv', 20 | 'UNSW_NB15_testing-set.csv', 21 | ] 22 | 23 | dataset = [] 24 | for filename in filenames: 25 | dataset.append(pd.read_csv(os.path.join(folder, filename))) 26 | 27 | dataset = pd.concat(dataset) 28 | 29 | # Removing rows with missing data and rows with infinite data 30 | dataset = dataset.replace([np.inf, -np.inf], np.nan) 31 | dataset = dataset.dropna() 32 | return dataset 33 | 34 | def preprocess_dataset(dataset, use_switch_features, bin_threshold): 35 | # Keeping some columns only 36 | dataset = dataset.drop(['label', 'service', 'state', 'proto', 'id'], axis=1) 37 | if use_switch_features: 38 | dataset = dataset.loc[:, dataset.columns.intersection(['dur', 'spkts', 'dpkts', 'sbytes', 39 | 'dbytes', 'sttl', 'dttl', 'sinpkt', 'dinpkt', 'swin', 'stcpb', 'dtcpb', 'dwin', 40 | 'tcprtt', 'synack', 'ackdat', 'ct_dst_ltm', 41 | 'ct_src_dport_ltm', 'ct_dst_sport_ltm', 'ct_dst_src_ltm', 'ct_src_ltm', 'attack_cat'])] 42 | 43 | if bin_threshold == -1: 44 | dataset.loc[dataset.attack_cat == 'Normal', 'attack_cat'] = 'Normal' 45 | dataset.loc[dataset.attack_cat != 'Normal', 'attack_cat'] = 'MALICIOUS' 46 | else: 47 | counts = dataset.attack_cat.value_counts() 48 | low_count_classes = counts[counts < bin_threshold] 49 | low_count_classes = low_count_classes.index.ravel() 50 | for c in low_count_classes: 51 | dataset.loc[dataset.attack_cat == c, 'attack_cat'] = 'OtherMalicious' 52 | 53 | return dataset 54 | 55 | def plot_feature_importance_mdi(model, features, filename): 56 | importances = pd.DataFrame({'feature' : features, 'importance' : model.feature_importances_}) 57 | importances = importances.sort_values('importance', ascending=False).set_index('feature') 58 | plt.rcParams['figure.figsize'] = (15, 5) 59 | fig, ax = plt.subplots() 60 | importances.plot.bar(ax=ax) 61 | ax.set_title("Feature importances using MDI") 62 | ax.set_ylabel("Mean decrease in impurity") 63 | fig.tight_layout() 64 | plt.savefig(filename + 'mdi.pdf', bbox_inches='tight') 65 | plt.close() 66 | 67 | def plot_permutation_importance(model, X_test, y_test, features, filename): 68 | result = permutation_importance(model, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2) 69 | importances = pd.DataFrame({'feature':features, 'importance' : result.importances_mean}) 70 | importances = importances.sort_values('importance', ascending=False).set_index('feature') 71 | plt.rcParams['figure.figsize'] = (10, 5) 72 | fig, ax = plt.subplots() 73 | importances.plot.bar(ax=ax) 74 | ax.set_title("Feature importances using permutation on full model") 75 | ax.set_ylabel("Mean accuracy decrease") 76 | fig.tight_layout() 77 | plt.savefig(filename + 'permutation.pdf', bbox_inches='tight') 78 | plt.close() 79 | 80 | def select_features(num_features, model, x, y, features): 81 | rfe = RFE(model, n_features_to_select=num_features) 82 | rfe.fit(x, y) 83 | feature_map = [(i, v) for i, v in itertools.zip_longest(rfe.get_support(), features)] 84 | map = [i[0] for i in feature_map] 85 | features = [] 86 | for i in feature_map: 87 | if i[0]: 88 | features.append(i[1]) 89 | 90 | return map, features 91 | 92 | def main(): 93 | os.mkdir('results-nb15') 94 | experiments = [(8, 256, 3, True, 3000), (7, 128, 4, True, 3000), (6, 64, 6, True, 3000), (5, 32, 10, True, 3000), (4, 16, 14, True, 3000), (14, 16384, 2, True, 3000), (13, 8192, 4, True, 3000), (12, 4096, 5, True, 3000), (11, 2096, 8, True, 3000), (10, 1024, 14, True, 3000)] 95 | 96 | 97 | boxs = [] 98 | results = [] 99 | for exp in experiments: 100 | # Training random forest tree 101 | filename = 'D' + str(exp[0]) + '-L' + str(exp[1]) + '-F' + str(exp[2]) + '-SWITCHFEATURES' + str(exp[3]) 102 | print(filename) 103 | 104 | dataset = read_and_clean_dataset('UNSW-NB15') 105 | dataset = preprocess_dataset(dataset, exp[3], exp[4]) 106 | 107 | print('Shape:', dataset.shape) 108 | print(dataset.attack_cat.value_counts()) 109 | num_classes = len(dataset.attack_cat.unique()) 110 | features = dataset.columns.tolist()[:-1] 111 | 112 | # Encoding labels 113 | labelencoder = LabelEncoder() 114 | y = labelencoder.fit_transform(dataset.attack_cat) 115 | dataset = dataset.drop(['attack_cat'], axis=1).values 116 | 117 | # Splitting up train and test sets 118 | X_train, X_test, y_train, y_test = train_test_split(dataset, y, train_size = 0.75, test_size = 0.25, stratify = y) 119 | 120 | model = DecisionTreeClassifier(max_depth=exp[0], max_leaf_nodes=exp[1], criterion='entropy', class_weight='balanced') 121 | 122 | map, features = select_features(exp[2], model, X_train, y_train, features) 123 | X_train = pd.DataFrame(X_train) 124 | X_test = pd.DataFrame(X_test) 125 | X_train = X_train.iloc[:, map] 126 | X_test = X_test.iloc[:, map] 127 | 128 | model.fit(X_train, y_train) 129 | 130 | # plot_feature_importance_mdi(model, features, filename) 131 | # plot_permutation_importance(model, X_test, y_test, features, filename) 132 | # return 133 | 134 | y_predict = model.predict(X_test) 135 | y_train_predict = model.predict(X_train) 136 | cm_test = confusion_matrix(y_test, y_predict) 137 | cm_train = confusion_matrix(y_train, y_train_predict) 138 | cm_test = cm_test.tolist() 139 | cm_train = cm_train.tolist() 140 | 141 | class_f1 = f1_score(y_test, y_predict, average=None) 142 | macro_f1 = f1_score(y_test, y_predict, average='macro') 143 | results.append(class_f1) 144 | boxs.append({ 145 | 'label' : 'Depth ' + str(exp[0]) + '\nLeaves ' + str(exp[1]) + '\nFeatures ' + str(exp[2]), 146 | 'whislo': min(class_f1), 147 | 'q1' : min(class_f1), 148 | 'med' : median(class_f1), 149 | 'q3' : max(class_f1), 150 | 'whishi': max(class_f1), 151 | 'mean' : mean(class_f1), 152 | 'fliers': [] 153 | }) 154 | print('Test set - Macro F1', macro_f1) 155 | 156 | lab = labelencoder.inverse_transform([x for x in range(num_classes)]) 157 | lab = lab.tolist() 158 | for i in range(len(cm_test)): 159 | cm_test[i].insert(0, 'Actual-' + lab[i]) 160 | cm_train[i].insert(0, 'Actual-' + lab[i]) 161 | 162 | lab.insert(0, 'Predicted-->') 163 | 164 | with open('results-nb15/results.csv', 'a') as my_csv: 165 | csvWriter = csv.writer(my_csv, delimiter=',') 166 | csvWriter.writerow([filename]) 167 | csvWriter.writerow([len(features)] + features) 168 | csvWriter.writerow(lab) 169 | csvWriter.writerows(cm_test) 170 | csvWriter.writerow(['F1 score'] + class_f1.tolist() + [macro_f1]) 171 | csvWriter.writerow(lab) 172 | csvWriter.writerows(cm_train) 173 | csvWriter.writerow(['=========================================']) 174 | 175 | out_filename = 'results-nb15/' + os.path.split(filename)[-1].split('.')[0] 176 | dot_filename = out_filename + '.dot' 177 | export_graphviz(model, out_file=dot_filename, class_names=labelencoder.inverse_transform([x for x in range(num_classes)]), feature_names=features, proportion = True) 178 | call(['dot', '-Tpdf', dot_filename, '-o', out_filename + '.pdf']) 179 | call(['rm', dot_filename]) 180 | with open('results-nb15/results.txt', 'a') as my_txt: 181 | my_txt.write(filename + '\n') 182 | my_txt.write(export_text(model, feature_names=features)) 183 | my_txt.write('=========================================\n') 184 | 185 | fig, ax = plt.subplots() 186 | ax.bxp(boxs, showfliers=False, showcaps=False, showmeans=True) 187 | ax.set_ylabel('F1 score') 188 | plt.savefig('results-nb15/nb15-box-plot.pdf', bbox_inches='tight') 189 | plt.close() 190 | 191 | if __name__ == '__main__': 192 | main() -------------------------------------------------------------------------------- /iisy/iisy.p4: -------------------------------------------------------------------------------- 1 | #include 2 | #if __TARGET_TOFINO__ == 3 3 | #include 4 | #elif __TARGET_TOFINO__ == 2 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | typedef bit<48> mac_addr_t; 11 | typedef bit<32> ipv4_addr_t; 12 | typedef bit<128> ipv6_addr_t; 13 | 14 | typedef bit<16> ether_type_t; 15 | const ether_type_t ETHERTYPE_IPV4 = 16w0x0800; 16 | 17 | typedef bit<8> ip_protocol_t; 18 | const ip_protocol_t IP_PROTOCOLS_TCP = 6; 19 | 20 | // 14 byte 21 | header ethernet_h { 22 | mac_addr_t dst_addr; 23 | mac_addr_t src_addr; 24 | bit<16> ether_type; 25 | } 26 | 27 | // 20 byte 28 | header ipv4_h { 29 | bit<4> version; 30 | bit<4> ihl; 31 | bit<8> diffserv; 32 | bit<16> total_len; 33 | bit<16> identification; 34 | bit<3> flags; 35 | bit<13> frag_offset; 36 | bit<8> ttl; 37 | bit<8> protocol; 38 | bit<16> hdr_checksum; 39 | ipv4_addr_t src_addr; 40 | ipv4_addr_t dst_addr; 41 | } 42 | 43 | // 20 byte 44 | header tcp_h { 45 | bit<16> src_port; 46 | bit<16> dst_port; 47 | bit<32> seq_no; 48 | bit<32> ack_no; 49 | bit<4> data_offset; 50 | bit<4> res; 51 | bit<1> cwr; 52 | bit<1> ece; 53 | bit<1> urg; 54 | bit<1> ack; 55 | bit<1> psh; 56 | bit<1> rst; 57 | bit<1> syn; 58 | bit<1> fin; 59 | bit<16> window; 60 | bit<16> checksum; 61 | bit<16> urgent_ptr; 62 | } 63 | 64 | #define FEATURE_WIDTH 16 65 | #define CODE_WIDTH 4 66 | #define FEATURE_TABLE_SIZE 20470 67 | #define LEAF_TABLE_SIZE 1099554 68 | 69 | header classification_t { 70 | bit<8> leaf; 71 | bit feature1; 72 | bit feature2; 73 | bit feature3; 74 | bit feature4; 75 | bit feature5; 76 | bit feature6; 77 | bit feature7; 78 | bit feature8; 79 | bit feature9; 80 | bit feature10; 81 | bit feature11; 82 | bit feature12; 83 | bit feature13; 84 | bit feature14; 85 | bit code1; 86 | bit code2; 87 | bit code3; 88 | bit code4; 89 | bit code5; 90 | bit code6; 91 | bit code7; 92 | bit code8; 93 | bit code9; 94 | bit code10; 95 | bit code11; 96 | bit code12; 97 | bit code13; 98 | bit code14; 99 | } 100 | 101 | header resubmit_header_t { 102 | bit<8> type; 103 | bit<8> class_id; 104 | } 105 | const bit<8> RESUB_TYPE = 255; 106 | const bit<3> DPRSR_DIGEST_TYPE = 0; 107 | 108 | struct header_t { 109 | ethernet_h ethernet; 110 | ipv4_h ipv4; 111 | tcp_h tcp; 112 | classification_t class; 113 | } 114 | 115 | #include "tofino-util.p4" 116 | 117 | struct metadata_t { 118 | bit<8> resub_type; 119 | resubmit_header_t resub_hdr; 120 | } 121 | 122 | typedef bit<9> egressSpec_t; 123 | 124 | // --------------------------------------------------------------------------- 125 | // Ingress parser 126 | // --------------------------------------------------------------------------- 127 | parser SwitchIngressParser( 128 | packet_in pkt, 129 | out header_t hdr, 130 | out metadata_t ig_md, 131 | out ingress_intrinsic_metadata_t ig_intr_md) { 132 | 133 | state start { 134 | pkt.extract(ig_intr_md); 135 | ig_md.resub_type = 0; 136 | transition select(ig_intr_md.resubmit_flag) { 137 | 1 : parse_resubmit; 138 | 0 : parse_port_metadata; 139 | } 140 | } 141 | 142 | state parse_resubmit { 143 | ig_md.resub_type = pkt.lookahead>()[7:0]; 144 | transition select(ig_md.resub_type) { 145 | RESUB_TYPE : parse_resub; 146 | default : reject; 147 | } 148 | } 149 | 150 | state parse_resub { 151 | pkt.extract(ig_md.resub_hdr); 152 | transition parse_resub_end; 153 | } 154 | 155 | state parse_resub_end { 156 | transition parse_ethernet; 157 | } 158 | 159 | state parse_port_metadata { 160 | pkt.advance(PORT_METADATA_SIZE); 161 | transition parse_ethernet; 162 | } 163 | 164 | state parse_ethernet { 165 | pkt.extract(hdr.ethernet); 166 | transition select(hdr.ethernet.ether_type) { 167 | ETHERTYPE_IPV4: parse_ipv4; 168 | default: reject; 169 | } 170 | } 171 | 172 | state parse_ipv4 { 173 | pkt.extract(hdr.ipv4); 174 | transition select(hdr.ipv4.protocol){ 175 | IP_PROTOCOLS_TCP: parse_tcp; 176 | default: reject; 177 | } 178 | } 179 | 180 | state parse_tcp { 181 | pkt.extract(hdr.tcp); 182 | transition parse_class_hdr; 183 | } 184 | 185 | state parse_class_hdr { 186 | pkt.extract(hdr.class); 187 | transition accept; 188 | } 189 | } 190 | 191 | // --------------------------------------------------------------------------- 192 | // Ingress Deparser 193 | // --------------------------------------------------------------------------- 194 | 195 | control SwitchIngressDeparser( 196 | packet_out pkt, 197 | inout header_t hdr, 198 | in metadata_t ig_md, 199 | in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md) { 200 | 201 | Checksum() ipv4_checksum; 202 | 203 | apply { 204 | hdr.ipv4.hdr_checksum = ipv4_checksum.update({ 205 | hdr.ipv4.version, 206 | hdr.ipv4.ihl, 207 | hdr.ipv4.diffserv, 208 | hdr.ipv4.total_len, 209 | hdr.ipv4.identification, 210 | hdr.ipv4.flags, 211 | hdr.ipv4.frag_offset, 212 | hdr.ipv4.ttl, 213 | hdr.ipv4.protocol, 214 | hdr.ipv4.src_addr, 215 | hdr.ipv4.dst_addr}); 216 | 217 | pkt.emit(hdr.ethernet); 218 | pkt.emit(hdr.ipv4); 219 | pkt.emit(hdr.tcp); 220 | pkt.emit(hdr.class); 221 | } 222 | } 223 | 224 | // --------------------------------------------------------------------------- 225 | // Ingress 226 | // --------------------------------------------------------------------------- 227 | control SwitchIngress( 228 | inout header_t hdr, 229 | inout metadata_t ig_md, 230 | in ingress_intrinsic_metadata_t ig_intr_md, 231 | in ingress_intrinsic_metadata_from_parser_t ig_prsr_md, 232 | inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md, 233 | inout ingress_intrinsic_metadata_for_tm_t ig_tm_md) { 234 | 235 | const PortId_t CPU_PORT = 64; 236 | 237 | action drop() { 238 | ig_dprsr_md.drop_ctl = 1; 239 | } 240 | 241 | action ipv4_forward(egressSpec_t port) { 242 | ig_tm_md.ucast_egress_port = port; 243 | hdr.ipv4.ttl = hdr.ipv4.ttl - 1; 244 | } 245 | 246 | action send_to_cpu() { 247 | ig_tm_md.ucast_egress_port = CPU_PORT; 248 | } 249 | 250 | table ipv4_exact { 251 | key = { 252 | hdr.ipv4.dst_addr: ternary; 253 | } 254 | actions = { 255 | ipv4_forward; 256 | drop; 257 | send_to_cpu; 258 | } 259 | size = 10000; 260 | default_action = send_to_cpu(); 261 | } 262 | 263 | action set_code1(bit code) { 264 | hdr.class.code1 = code; 265 | } 266 | 267 | table f1 { 268 | key = { 269 | hdr.class.feature1: ternary; 270 | } 271 | actions = { 272 | set_code1; 273 | NoAction; 274 | } 275 | size = FEATURE_TABLE_SIZE; 276 | default_action = NoAction(); 277 | } 278 | 279 | action set_code2(bit code) { 280 | hdr.class.code2 = code; 281 | } 282 | 283 | table f2 { 284 | key = { 285 | hdr.class.feature2: ternary; 286 | } 287 | actions = { 288 | set_code2; 289 | NoAction; 290 | } 291 | size = FEATURE_TABLE_SIZE; 292 | default_action = NoAction(); 293 | } 294 | 295 | action set_code3(bit code) { 296 | hdr.class.code3 = code; 297 | } 298 | 299 | table f3 { 300 | key = { 301 | hdr.class.feature3: ternary; 302 | } 303 | actions = { 304 | set_code3; 305 | NoAction; 306 | } 307 | size = FEATURE_TABLE_SIZE; 308 | default_action = NoAction(); 309 | } 310 | action set_code4(bit code) { 311 | hdr.class.code4 = code; 312 | } 313 | 314 | table f4 { 315 | key = { 316 | hdr.class.feature4: ternary; 317 | } 318 | actions = { 319 | set_code4; 320 | NoAction; 321 | } 322 | size = FEATURE_TABLE_SIZE; 323 | default_action = NoAction(); 324 | } 325 | 326 | action set_code5(bit code) { 327 | hdr.class.code5 = code; 328 | } 329 | 330 | table f5 { 331 | key = { 332 | hdr.class.feature5: ternary; 333 | } 334 | actions = { 335 | set_code5; 336 | NoAction; 337 | } 338 | size = FEATURE_TABLE_SIZE; 339 | default_action = NoAction(); 340 | } 341 | 342 | action set_code6(bit code) { 343 | hdr.class.code6 = code; 344 | } 345 | 346 | table f6 { 347 | key = { 348 | hdr.class.feature6: ternary; 349 | } 350 | actions = { 351 | set_code6; 352 | NoAction; 353 | } 354 | size = FEATURE_TABLE_SIZE; 355 | default_action = NoAction(); 356 | } 357 | 358 | action set_code7(bit code) { 359 | hdr.class.code7 = code; 360 | } 361 | 362 | table f7 { 363 | key = { 364 | hdr.class.feature7: ternary; 365 | } 366 | actions = { 367 | set_code7; 368 | NoAction; 369 | } 370 | size = FEATURE_TABLE_SIZE; 371 | default_action = NoAction(); 372 | } 373 | 374 | action set_code8(bit code) { 375 | hdr.class.code8 = code; 376 | } 377 | 378 | table f8 { 379 | key = { 380 | hdr.class.feature8: ternary; 381 | } 382 | actions = { 383 | set_code8; 384 | NoAction; 385 | } 386 | size = FEATURE_TABLE_SIZE; 387 | default_action = NoAction(); 388 | } 389 | 390 | action set_code9(bit code) { 391 | hdr.class.code9 = code; 392 | } 393 | 394 | table f9 { 395 | key = { 396 | hdr.class.feature9: ternary; 397 | } 398 | actions = { 399 | set_code9; 400 | NoAction; 401 | } 402 | size = FEATURE_TABLE_SIZE; 403 | default_action = NoAction(); 404 | } 405 | 406 | action set_code10(bit code) { 407 | hdr.class.code10 = code; 408 | } 409 | 410 | table f10 { 411 | key = { 412 | hdr.class.feature10: ternary; 413 | } 414 | actions = { 415 | set_code10; 416 | NoAction; 417 | } 418 | size = FEATURE_TABLE_SIZE; 419 | default_action = NoAction(); 420 | } 421 | 422 | action set_code11(bit code) { 423 | hdr.class.code11 = code; 424 | } 425 | 426 | table f11 { 427 | key = { 428 | hdr.class.feature11: ternary; 429 | } 430 | actions = { 431 | set_code11; 432 | NoAction; 433 | } 434 | size = FEATURE_TABLE_SIZE; 435 | default_action = NoAction(); 436 | } 437 | 438 | action set_code12(bit code) { 439 | hdr.class.code12 = code; 440 | } 441 | 442 | table f12 { 443 | key = { 444 | hdr.class.feature12: ternary; 445 | } 446 | actions = { 447 | set_code12; 448 | NoAction; 449 | } 450 | size = FEATURE_TABLE_SIZE; 451 | default_action = NoAction(); 452 | } 453 | 454 | action set_leaf(bit<8> leaf) { 455 | hdr.class.leaf = leaf; 456 | } 457 | 458 | table leaf_table { 459 | key = { 460 | hdr.class.code1: ternary; 461 | hdr.class.code2: ternary; 462 | hdr.class.code3: ternary; 463 | hdr.class.code4: ternary; 464 | hdr.class.code5: ternary; 465 | hdr.class.code6: ternary; 466 | hdr.class.code7: ternary; 467 | hdr.class.code8: ternary; 468 | hdr.class.code9: ternary; 469 | hdr.class.code10: ternary; 470 | hdr.class.code11: ternary; 471 | hdr.class.code12: ternary; 472 | 473 | } 474 | actions = { 475 | set_leaf; 476 | NoAction; 477 | } 478 | size = LEAF_TABLE_SIZE; 479 | default_action = NoAction(); 480 | } 481 | 482 | 483 | apply { 484 | f1.apply(); 485 | f2.apply(); 486 | f3.apply(); 487 | f4.apply(); 488 | f5.apply(); 489 | f6.apply(); 490 | f7.apply(); 491 | f8.apply(); 492 | f9.apply(); 493 | f10.apply(); 494 | f11.apply(); 495 | f12.apply(); 496 | leaf_table.apply(); 497 | 498 | if (hdr.ipv4.isValid()) { 499 | ipv4_exact.apply(); 500 | } 501 | } 502 | } 503 | 504 | // --------------------------------------------------------------------------- 505 | // Egress Parser 506 | // --------------------------------------------------------------------------- 507 | parser SwitchEgressParser( 508 | packet_in pkt, 509 | out header_t hdr, 510 | out metadata_t eg_md, 511 | out egress_intrinsic_metadata_t eg_intr_md) { 512 | 513 | TofinoEgressParser() tofino_parser; 514 | 515 | state start { 516 | tofino_parser.apply(pkt, eg_intr_md); 517 | transition parse_ethernet; 518 | } 519 | 520 | state parse_ethernet { 521 | pkt.extract(hdr.ethernet); 522 | transition select(hdr.ethernet.ether_type) { 523 | ETHERTYPE_IPV4 : parse_ipv4; 524 | default : reject; 525 | } 526 | } 527 | 528 | state parse_ipv4 { 529 | pkt.extract(hdr.ipv4); 530 | transition select(hdr.ipv4.protocol){ 531 | IP_PROTOCOLS_TCP: parse_tcp; 532 | default: reject; 533 | } 534 | } 535 | 536 | state parse_tcp { 537 | pkt.extract(hdr.tcp); 538 | transition parse_class_hdr; 539 | } 540 | 541 | state parse_class_hdr { 542 | pkt.extract(hdr.class); 543 | transition accept; 544 | } 545 | } 546 | 547 | 548 | // --------------------------------------------------------------------------- 549 | // Egress 550 | // --------------------------------------------------------------------------- 551 | control SwitchEgress( 552 | inout header_t hdr, 553 | inout metadata_t eg_md, 554 | in egress_intrinsic_metadata_t eg_intr_md, 555 | in egress_intrinsic_metadata_from_parser_t eg_intr_from_prsr, 556 | inout egress_intrinsic_metadata_for_deparser_t eg_intr_md_for_dprsr, 557 | inout egress_intrinsic_metadata_for_output_port_t eg_intr_md_for_oport) { 558 | 559 | apply { 560 | } 561 | } 562 | 563 | // --------------------------------------------------------------------------- 564 | // Egress Deparser 565 | // --------------------------------------------------------------------------- 566 | control SwitchEgressDeparser(packet_out pkt, 567 | inout header_t hdr, 568 | in metadata_t eg_md, 569 | in egress_intrinsic_metadata_for_deparser_t 570 | eg_intr_dprsr_md 571 | ) { 572 | 573 | apply { 574 | pkt.emit(hdr.ethernet); 575 | pkt.emit(hdr.ipv4); 576 | pkt.emit(hdr.tcp); 577 | pkt.emit(hdr.class); 578 | } 579 | } 580 | 581 | Pipeline(SwitchIngressParser(), 582 | SwitchIngress(), 583 | SwitchIngressDeparser(), 584 | SwitchEgressParser(), 585 | SwitchEgress(), 586 | SwitchEgressDeparser()) pipe; 587 | 588 | Switch(pipe) main; -------------------------------------------------------------------------------- /iisy/resource-model.py: -------------------------------------------------------------------------------- 1 | import math 2 | import argparse 3 | 4 | def proposition_1_example(n, d, k): 5 | num_leaves = 2 ** d 6 | feature_table_size = k - math.ceil((k / num_leaves)) 7 | leaf_table_size = math.ceil((num_leaves - 1) / num_leaves * ((((num_leaves - 1) / n) + 1) ** n)) 8 | print('Feature table size (each):', feature_table_size) 9 | print('Leaf table size:', leaf_table_size) 10 | print('Total size:', (n * feature_table_size) + leaf_table_size) 11 | 12 | def proposition_2_depth(n, k): 13 | return n + math.ceil(math.log2(k)) 14 | 15 | def proposition_2_num_leaf_nodes(n, k): 16 | return (n ** 2) + (n * (k - 3)) + 2 17 | 18 | def proposition_2_num_tcam_entries_An2(n, k): 19 | m = math.ceil(math.log2(k - 1)) 20 | return m ** (n - 1) 21 | 22 | def proposition_2_num_sram_entries_An2(n, k): 23 | return (k - 1) ** (n - 1) 24 | 25 | def proposition_2_num_sram_total(n, N, k): 26 | if n == 1: 27 | return (N * (k - 1)) 28 | 29 | total = 0 30 | for n_curr in range(2, n + 1): #[2 to n-1] 31 | total += (k - 1) ** n_curr 32 | 33 | for n_curr in range(2, n): 34 | total += (k - 1) ** 2 35 | 36 | return total + proposition_2_num_sram_total(n - 1, N, k) 37 | 38 | def proposition_2_num_tcam_total(n, N, k): 39 | if n == 1: 40 | return (N * (k - 1)) 41 | 42 | total = 0 43 | for n_curr in range(2, n + 1): #[2 to n-1] 44 | total += math.ceil(math.log2((k - 1))) ** n_curr 45 | 46 | for n_curr in range(2, n): 47 | total += math.ceil(math.log2((k - 1))) ** 2 48 | 49 | return total + proposition_2_num_tcam_total(n - 1, N, k) 50 | 51 | def main(): 52 | parser = argparse.ArgumentParser( 53 | description='This program implements the propositions 1 and 2 presented in the paper to model IIsy resource consumption.') 54 | 55 | subparsers = parser.add_subparsers(required=True, dest='subcommand') 56 | 57 | p1_args = subparsers.add_parser('p1', help='Apply proposition 1 model.') 58 | p2_args = subparsers.add_parser('p2', help='Apply proposition 2 model.') 59 | 60 | p1_args.add_argument('--n', type=int, required=True, help='The number of features.') 61 | p1_args.add_argument('--d', type=int, required=True, help='The depth of the tree (excluding leaf layer).') 62 | p1_args.add_argument('--k', type=int, required=True, help='The maximum feature value.') 63 | 64 | p2_args.add_argument('--filename', type=str, required=True, help='The output CSV file name containing the results of applying proposition 2 to a number of N, K combinations.') 65 | p2_args.add_argument('--N_max', type=int, required=True, help='The maximum number of features to explore up to. For example, N_max=5 will explore N=2,3,4,5') 66 | p2_args.add_argument('--K_power_max', type=int, required=True, help='The maximum feature value K to explore up to. Represented as a power of 2. For example, K_power_max=4 will explore K=3,7,15)') 67 | args = parser.parse_args() 68 | 69 | if args.subcommand == 'p1': 70 | proposition_1_example(args.n, args.d, args.k) 71 | elif args.subcommand == 'p2': 72 | f = open(args.filename, 'w') 73 | f.write('N (Number of features), K (Maximum feature value), Number of leaves, Depth, Number of A_{n-2} tcam entries, num_tcam_total (excl. default)\n') 74 | # n = 9 75 | for n in range(2, args.N_max + 1): 76 | for k_pow in range(2, args.K_power_max + 1): 77 | k = (2 ** k_pow) - 1 78 | f.write(str(n) + ',' + str(k) + ',' + str(proposition_2_num_leaf_nodes(n, k)) + ','+ str(proposition_2_depth(n, k)) + ',' + str(proposition_2_num_tcam_entries_An2(n, k)) + ',' + str(proposition_2_num_tcam_total(n, n, k) - (math.ceil(math.log2(k-1)) ** n)) + '\n') 79 | f.flush() 80 | 81 | f.close() 82 | 83 | if __name__ == '__main__': 84 | main() -------------------------------------------------------------------------------- /iisy/worst-case-feature-table.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | def int_to_binary_str(n, width): 4 | binary = '' 5 | i = 1 << (width - 1) 6 | while i > 0: 7 | if (n & i) != 0: 8 | binary += '1' 9 | else : 10 | binary += '0' 11 | 12 | i = i // 2 13 | return binary 14 | 15 | def collapse_wildcard_pair(a, b, width): 16 | a = list(a) 17 | num_match = 0 18 | wildcard_ind = -1 19 | for i in range(len(a) -1, -1, -1): 20 | if wildcard_ind == -1 and a[i] != b[i]: 21 | wildcard_ind = i 22 | if a[i] == b[i]: 23 | num_match += 1 24 | 25 | if num_match == (width - 1) and wildcard_ind != -1: 26 | a[wildcard_ind] = '*' 27 | return ''.join(a) 28 | return None 29 | 30 | def collapse_adjacent(strs, width): 31 | i = 0 32 | j = 1 33 | collapsed_last_round = False 34 | while len(strs) > 1: 35 | s = strs[i] 36 | s2 = strs[j] 37 | collapsed = collapse_wildcard_pair(s, s2, width) 38 | if collapsed: 39 | strs.remove(s) 40 | strs.remove(s2) 41 | strs.insert(i, collapsed) 42 | collapsed_last_round = True 43 | else: 44 | i += 1 45 | j += 1 46 | 47 | if j >= len(strs): 48 | if collapsed_last_round: 49 | i = 0 50 | j = 1 51 | collapsed_last_round = False 52 | else: 53 | break 54 | 55 | return strs 56 | 57 | def tcam_rules_range(lower, upper, width): 58 | numbers_less_than = [] 59 | for i in range(lower, upper + 1): 60 | numbers_less_than.append(int_to_binary_str(i, width)) 61 | 62 | return collapse_adjacent(numbers_less_than, width) 63 | 64 | def special_example_split_largest_into_halves(lower, upper, num_splits): 65 | if num_splits < 1: 66 | return None 67 | 68 | config = [(lower, lower), (1, upper)] 69 | for s in range(num_splits - 1): 70 | max_split_ind = -1 71 | max_split = -1 72 | for i in range(len(config)): 73 | size = config[i][1] - config[i][0] 74 | if size > max_split: 75 | max_split_ind = i 76 | max_split = size 77 | 78 | max_split = int(max_split / 2) 79 | 80 | max_split_upper = config[max_split_ind][1] 81 | config[max_split_ind] = (config[max_split_ind][0], config[max_split_ind][0] + max_split) 82 | new_split = (config[max_split_ind][1] + 1, max_split_upper) 83 | config.insert(max_split_ind + 1, new_split) 84 | 85 | return config 86 | 87 | def main(): 88 | parser = argparse.ArgumentParser( 89 | description='This program generates the worst-case feature table split for IIsy using TCAM.') 90 | 91 | parser.add_argument('--width', type=int, required=True, help='Feature width (number of bits)') 92 | parser.add_argument('--upper_lim', type=int, required=True, help='Maximum feature value') 93 | parser.add_argument('--leaves', type=int, required=True, help='Number of leaves in the tree.') 94 | args = parser.parse_args() 95 | 96 | if args.upper_lim > (2 ** args.width) - 1: 97 | args.upper_lim = (2 ** args.width) - 1 98 | 99 | lower = 0 100 | splits = args.leaves - 1 101 | 102 | print('{0:22} | {1:15} | {2}'.format('Leaf Range', '# of TCAM rules', 'TCAM Rules')) 103 | config = special_example_split_largest_into_halves(lower, args.upper_lim, splits) 104 | breakdown = '' 105 | total = 0 106 | maxx = 0 107 | for split in config: 108 | tcam = tcam_rules_range(split[0], split[1], args.width) 109 | breakdown += "{0:6} >= AND <= {1:5} | {2:15} | {3}\n".format(split[0], split[1], len(tcam), str(tcam)) 110 | total += len(tcam) 111 | if len(tcam) > maxx: 112 | maxx = len(tcam) 113 | 114 | print(breakdown) 115 | print('Total rules:', total) 116 | print('Total rules exluding largest split (as default rule):', (total - maxx)) 117 | print('=============================================================================================') 118 | 119 | if __name__ == '__main__': 120 | main() -------------------------------------------------------------------------------- /leo-generator/leo_ctrlplane_generator.py: -------------------------------------------------------------------------------- 1 | import math 2 | import importlib 3 | import sys 4 | from leo_templates import * 5 | 6 | class InternalNode: 7 | def __init__(self, feature, constraint, depth): 8 | self.feature = feature 9 | self.constraint = constraint 10 | self.depth = depth 11 | self.left = None 12 | self.right = None 13 | 14 | class LeafNode: 15 | def __init__(self, label, depth): 16 | self.label = label 17 | self.depth = depth 18 | 19 | class Tree: 20 | def __init__(self, node): 21 | self.root = node 22 | 23 | def print_tree(self, node, level, prefix='ROOT'): 24 | if node is not None: 25 | if type(node) == InternalNode: 26 | print('| ' * level + prefix, node.feature, node.constraint) 27 | if node.left is not None or node.right is not None: 28 | self.print_tree(node.left, level + 1, 'L ') 29 | self.print_tree(node.right, level + 1, 'R ') 30 | else: 31 | print('| ' * level + prefix, node.label) 32 | 33 | def parse_line(line): 34 | line = line.replace('|---', '| ') 35 | depth = line.count('| ') 36 | leaf = 'class' in line 37 | line = line.strip('| ') 38 | line = line.split(' ') 39 | if leaf: 40 | label = int(line[1]) 41 | return (leaf, depth, label) 42 | else: 43 | feature = line[0] 44 | condition = line[1] 45 | constraint = int(round(float(line[-1]))) 46 | return (leaf, depth, feature, condition, constraint) 47 | 48 | def find_my_right(node_lines, line_num, depth): 49 | for i in range(line_num, len(node_lines)): 50 | if node_lines[i][1] == depth: 51 | return i 52 | 53 | return None 54 | 55 | def build_tree_recursive(node_lines, node, line_num): 56 | if line_num >= len(node_lines): 57 | return None 58 | 59 | tup = node_lines[line_num] 60 | if tup[0]: 61 | return None 62 | else: 63 | right_subtree_line_num = 1 + find_my_right(node_lines, line_num + 1, tup[1]) 64 | right_node = node_lines[right_subtree_line_num] 65 | left_node = node_lines[line_num + 1] 66 | 67 | if left_node[0]: 68 | node.left = LeafNode(left_node[2], left_node[1]) 69 | else: 70 | node.left = InternalNode(left_node[2], left_node[4], left_node[1]) 71 | build_tree_recursive(node_lines, node.left, line_num + 1) 72 | 73 | if right_node[0]: 74 | node.right = LeafNode(right_node[2], right_node[1]) 75 | else: 76 | node.right = InternalNode(right_node[2], right_node[4], right_node[1]) 77 | build_tree_recursive(node_lines, node.right, right_subtree_line_num) 78 | 79 | return node 80 | 81 | def build_tree_from_file(file): 82 | f = open(file, 'r') 83 | lines = f.readlines() 84 | f.close() 85 | 86 | nodes = [] 87 | for line in lines: 88 | nodes.append(parse_line(line)) 89 | 90 | root = InternalNode(nodes[0][2], nodes[0][4], nodes[0][1]) 91 | build_tree_recursive(nodes, root, 0) 92 | tree = Tree(root) 93 | return tree 94 | 95 | def find_k_children(node, k): 96 | children = [] 97 | queue = [node] 98 | while len(queue) > 0: 99 | cur_node = queue.pop(0) 100 | children.append(cur_node) 101 | if len(children) == k: 102 | break 103 | 104 | if type(cur_node.left) == InternalNode: 105 | queue.append(cur_node.left) 106 | 107 | if type(cur_node.right) == InternalNode: 108 | queue.append(cur_node.right) 109 | 110 | return children 111 | 112 | def sub_tree_splitter(root, K): 113 | bfs_sorted_nodes = [] 114 | 115 | bfs_queue = [root] 116 | while len(bfs_queue) > 0: 117 | node = bfs_queue.pop(0) 118 | bfs_sorted_nodes.append(node) 119 | 120 | if type(node.left) == InternalNode: 121 | bfs_queue.append(node.left) 122 | if type(node.right) == InternalNode: 123 | bfs_queue.append(node.right) 124 | 125 | sub_groups = [] 126 | while len(bfs_sorted_nodes) > 0: 127 | node = bfs_sorted_nodes[0] 128 | children = find_k_children(node, K) 129 | sub_groups.append(children) 130 | for c in children: 131 | bfs_sorted_nodes.remove(c) 132 | 133 | return sub_groups 134 | 135 | def assign_rule_to_layers(sub_groups, subtree_layer_limits): 136 | assigned_layers = [] 137 | for layer in range(1, len(subtree_layer_limits) + 1): 138 | layer_limit = subtree_layer_limits[layer - 1] 139 | print('Layer', layer, '| Available space:', layer_limit) 140 | curr_group = [] 141 | for i in range(layer_limit): 142 | if len(sub_groups) != 0: 143 | rule = sub_groups.pop(0) 144 | curr_group.append(rule) 145 | for r in rule: 146 | print(r.feature, r.constraint, end=', ' ) 147 | print() 148 | 149 | assigned_layers.append((layer, curr_group)) 150 | 151 | if len(sub_groups) > 0: 152 | print('Error: Not all rules were assigned to a layer') 153 | 154 | return assigned_layers 155 | 156 | def generate_runtime_code(layers, k): 157 | for layer in layers: 158 | for alu in range(1, k + 1): 159 | clear_table = clear_table_t.substitute(layer_id=layer[0], alu=alu) 160 | print(clear_table) 161 | 162 | def main(): 163 | filename = 'tree-example.txt' 164 | k = 2 165 | num_layers = 3 166 | 167 | sys.path.append('..') 168 | leo_resource_model = importlib.import_module('leo.resource-model') 169 | 170 | alu_config = [k] * num_layers 171 | subtree_layer_limits = leo_resource_model.leo_model(alu_config, False, False) 172 | subtree_layer_limits = subtree_layer_limits[:-1] 173 | 174 | tree = build_tree_from_file(filename) 175 | sub_groups = sub_tree_splitter(tree.root, k) 176 | layers = assign_rule_to_layers(sub_groups, subtree_layer_limits) 177 | generate_runtime_code(layers, k) 178 | 179 | if __name__ == '__main__': 180 | main() -------------------------------------------------------------------------------- /leo-generator/leo_dataplane_generator.py: -------------------------------------------------------------------------------- 1 | from leo_sram import leo_sram_gen 2 | from leo_tcam import leo_tcam_gen 3 | 4 | import argparse 5 | import math 6 | 7 | def main(): 8 | parser = argparse.ArgumentParser( 9 | description='This program generates P4 code for Leo SRAM/TCAM for a target tree class.') 10 | 11 | grouped_args = parser.add_mutually_exclusive_group(required=True) 12 | grouped_args.add_argument('--sram', action='store_true', help='Use SRAM memory.') 13 | grouped_args.add_argument('--tcam', action='store_true', help='Use TCAM memory.') 14 | 15 | parser.add_argument('--filename', type=str, required=True, help='The output file name containing generated P4 code.') 16 | parser.add_argument('--sub_tree', type=int, required=True, help='Depth of sub-tree (2 = 3 nodes in a layer, 3 = 7 nodes in a layer, etc.)') 17 | parser.add_argument('--depth', type=int, required=True, help='The depth of the tree class (Excluding leaf layer).') 18 | parser.add_argument('--features', type=int, required=True, help='The number of features supported in the tree class.') 19 | parser.add_argument('--leaf_limit', type=int, default=0, help='If the tree class has a limit on the number of leaves (Exclude this argument if no limit).') 20 | parser.add_argument('--transient', action='store_true', help='Enable support for transient state during runtime tree updates.') 21 | args = parser.parse_args() 22 | 23 | layers = int(math.ceil(args.depth / args.sub_tree)) 24 | 25 | if args.tcam: 26 | code = leo_tcam_gen(args.sub_tree, layers, args.features, args.leaf_limit, args.transient) 27 | elif args.sram: 28 | code = leo_sram_gen(args.sub_tree, layers, args.features, args.transient) 29 | 30 | f = open(args.filename, 'w') 31 | f.writelines(code) 32 | f.close() 33 | 34 | 35 | if __name__ == '__main__': 36 | main() -------------------------------------------------------------------------------- /leo-generator/leo_sram.py: -------------------------------------------------------------------------------- 1 | from leo_templates import * 2 | 3 | def layer_gen(num_alus, num_features, layer_id, sub_tree, transient): 4 | code = [] 5 | 6 | for a in range(1, num_alus + 1): 7 | 8 | # first ALU of layer 2 and layer responsible for setting leaf 9 | if a == 1 and layer_id > 1: 10 | actions_for_table = '\n\t\t\tset_leaf;' 11 | else: 12 | actions_for_table = '' 13 | 14 | for f in range(1, num_features + 1): 15 | # first ALU of layer 2 and layer responsible for compressing prev. layers into cell ID 16 | if a == 1 and layer_id > 1: 17 | action = mux_action_decl_with_result_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f, 'layer_prev' : layer_id - 1}) 18 | else: 19 | action = mux_action_decl_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f}) 20 | 21 | actions_for_table += mux_action_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f}) 22 | code.append(action) 23 | 24 | if layer_id == 1: 25 | keys = mux_key_t.substitute({'key_name' : 'tree_id', 'table_type' : 'exact'}) 26 | else: 27 | keys = '' 28 | if transient and layer_id == 2: 29 | keys += mux_key_t.substitute({'key_name' : 'tree_id', 'table_type' : 'exact'}) 30 | if layer_id > 2: 31 | keys += mux_key_t.substitute({'key_name' : 'layer_' + str(layer_id - 2) + '_result', 'table_type' : 'exact'}) 32 | 33 | for a2 in range(1, num_alus + 1): 34 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_result', 'table_type' : 'exact'}) 35 | 36 | table_size = 2 ** ((sub_tree * layer_id) - sub_tree) 37 | if layer_id > 1: 38 | table_size = (2 ** num_alus) * (2 ** ((sub_tree * (layer_id - 1)) - sub_tree)) 39 | 40 | if transient: 41 | table_size = table_size * 2 42 | 43 | table = mux_table_t.substitute({'layer' : layer_id, 'alu' : a, 'table_size' : int(table_size), 'actions': actions_for_table, 'keys' : keys}) 44 | code.append(table) 45 | 46 | return code 47 | 48 | def custom_hdrs_gen(num_layers, num_alus, num_features): 49 | features = '' 50 | for f in range(1, num_features + 1): 51 | features += '\tbit feature_' + str(f) + ';\n' 52 | 53 | layer_results = '' 54 | for l in range(1, num_layers): 55 | layer_results += '\tbit layer_' + str(l) + '_result;\n' 56 | 57 | alu_hdrs = '' 58 | for a in range(1, num_alus + 1): 59 | alu_hdrs += '\tbit alu_' + str(a) + '_input;\n' 60 | alu_hdrs += '\tbit alu_' + str(a) + '_result;\n' 61 | # if num_alus % 8 != 0: 62 | # pad = 8 - (num_alus % 8) 63 | # alu_hdrs += '\tbit<' + str(pad) + '> padding;\n' 64 | 65 | hdrs = custom_header_t.substitute({'hdrs' : layer_results + alu_hdrs + features}) 66 | return hdrs 67 | 68 | def apply_block_gen(num_layers, num_alus): 69 | layer_calls = '' 70 | for l in range(1, num_layers + 1): 71 | for a in range(1, num_alus + 1): 72 | layer_calls += '\t\tlayer_' + str(l) + '_' + str(a) + '.apply();\n' 73 | 74 | for a in range(1, num_alus + 1): 75 | layer_calls += '\t\tALU_' + str(a) + '_and();\n' 76 | 77 | layer_calls += '\t\tlayer_' + str(num_layers + 1) + '_1.apply();\n' 78 | apply_block = apply_t.substitute({'layer_apply' : layer_calls}) 79 | return apply_block 80 | 81 | def final_table_gen(num_layers, num_alus, sub_tree, transient): 82 | # If one layer only, no grand-father to match on 83 | if num_layers > 1: 84 | keys = mux_key_t.substitute({'key_name' : 'layer_' + str(num_layers - 1) + '_result', 'table_type' : 'exact'}) 85 | else: 86 | keys = '' 87 | 88 | # Add ALU results to key 89 | for a2 in range(1, num_alus + 1): 90 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_result', 'table_type' : 'exact'}) 91 | 92 | table_size = 2 ** ((sub_tree * (num_layers + 1)) - sub_tree) 93 | table_size = (2 ** num_alus) * (2 ** ((sub_tree * num_layers) - sub_tree)) 94 | 95 | if transient: 96 | table_size = table_size * 2 97 | 98 | final_table = mux_table_t.substitute({'layer' : num_layers + 1, 'alu' : '1', 'table_size' : int(table_size), 'actions': '\n\t\t\tset_leaf;', 'keys' : keys}) 99 | return final_table 100 | 101 | def leo_sram_gen(sub_tree, num_layers, num_features, transient): 102 | num_alus = (2 ** sub_tree) - 1 103 | 104 | alu_code = '' 105 | for a in range(1, num_alus + 1): 106 | alu = stateless_AND_alu_T.substitute({'alu' : a}) 107 | alu_code += alu 108 | 109 | layers = [] 110 | for l in range(1, num_layers + 1): 111 | layers += layer_gen(num_alus, num_features, l, sub_tree, transient) 112 | 113 | final_table = final_table_gen(num_layers, num_alus, sub_tree, transient) 114 | custom_hdrs = custom_hdrs_gen(num_layers, num_alus, num_features) 115 | apply_block = apply_block_gen(num_layers, num_alus) 116 | 117 | code = [std_headers] + [custom_hdrs] + [ingress_parser_deparser] + [egress_parser_deparser] + [alu_code] + layers + [final_table] + [apply_block] + [footer] 118 | return code -------------------------------------------------------------------------------- /leo-generator/leo_tcam.py: -------------------------------------------------------------------------------- 1 | from leo_templates import * 2 | 3 | def layer_gen(num_alus, num_features, layer_id, sub_tree, leaf_limit, transient): 4 | code = [] 5 | 6 | for a in range(1, num_alus + 1): 7 | 8 | # first ALU of layer 2 and layer responsible for setting leaf 9 | if a == 1 and layer_id > 1: 10 | actions_for_table = '\n\t\tset_leaf;' 11 | else: 12 | actions_for_table = '' 13 | 14 | for f in range(1, num_features + 1): 15 | # first ALU of layer 2 and layer responsible for compressing prev. layers into cell ID 16 | if a == 1 and layer_id > 1: 17 | if layer_id % 2 == 0: 18 | action = mux_action_alt_decl_with_result_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f, 'layer_prev' : layer_id - 1}) 19 | else: 20 | action = mux_action_decl_with_result_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f, 'layer_prev' : layer_id - 1}) 21 | else: 22 | if layer_id % 2 == 0: 23 | action = mux_action_alt_decl_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f}) 24 | else: 25 | action = mux_action_decl_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f}) 26 | 27 | actions_for_table += mux_action_t.substitute({'layer' : layer_id, 'alu' : a, 'feature' : f}) 28 | code.append(action) 29 | 30 | if layer_id == 1: 31 | keys = mux_key_t.substitute({'key_name' : 'tree_id', 'table_type' : 'ternary'}) 32 | else: 33 | keys = '' 34 | if transient and layer_id == 2: 35 | keys += mux_key_t.substitute({'key_name' : 'tree_id', 'table_type' : 'ternary'}) 36 | if layer_id > 2: 37 | keys += mux_key_t.substitute({'key_name' : 'layer_' + str(layer_id - 2) + '_result', 'table_type' : 'ternary'}) 38 | 39 | for a2 in range(1, num_alus + 1): 40 | if layer_id % 2 == 0: 41 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_input', 'table_type' : 'ternary'}) 42 | else: 43 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_input_B', 'table_type' : 'ternary'}) 44 | 45 | table_size = 2 ** ((sub_tree * layer_id) - sub_tree) 46 | if leaf_limit != 0: 47 | table_size = min(table_size, leaf_limit) 48 | 49 | if transient: 50 | table_size = table_size * 2 51 | 52 | table = mux_table_t.substitute({'layer' : layer_id, 'alu' : a, 'table_size' : int(table_size), 'actions': actions_for_table, 'keys' : keys}) 53 | code.append(table) 54 | 55 | return code 56 | 57 | def custom_hdrs_gen(num_layers, num_alus, num_features): 58 | features = '' 59 | for f in range(1, num_features + 1): 60 | features += '\tbit feature_' + str(f) + ';\n' 61 | 62 | layer_results = '' 63 | for l in range(1, num_layers): 64 | layer_results += '\tbit layer_' + str(l) + '_result;\n' 65 | 66 | alu_hdrs = '' 67 | for a in range(1, num_alus + 1): 68 | alu_hdrs += '\tbit alu_' + str(a) + '_input;\n' 69 | alu_hdrs += '\tbit alu_' + str(a) + '_input_B;\n' 70 | # if num_alus % 8 != 0: 71 | # pad = 8 - (num_alus % 8) 72 | # alu_hdrs += '\tbit<' + str(pad) + '> padding;\n' 73 | 74 | hdrs = custom_header_t.substitute({'hdrs' : layer_results + alu_hdrs + features}) 75 | return hdrs 76 | 77 | def apply_block_gen(num_layers, num_alus): 78 | layer_calls = '' 79 | for l in range(1, num_layers + 1): 80 | for a in range(1, num_alus + 1): 81 | layer_calls += '\t\tlayer_' + str(l) + '_' + str(a) + '.apply();\n' 82 | 83 | layer_calls += '\t\tlayer_' + str(num_layers + 1) + '_1.apply();\n' 84 | apply_block = apply_t.substitute({'layer_apply' : layer_calls}) 85 | return apply_block 86 | 87 | def final_table_gen(num_layers, num_alus, sub_tree, leaf_limit, transient): 88 | # If one layer only, no grand-father to match on 89 | if num_layers > 1: 90 | keys = mux_key_t.substitute({'key_name' : 'layer_' + str(num_layers - 1) + '_result', 'table_type' : 'ternary'}) 91 | else: 92 | keys = '' 93 | 94 | # Add ALU results to key 95 | for a2 in range(1, num_alus + 1): 96 | if (num_layers + 1) % 2 == 0: 97 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_input', 'table_type' : 'ternary'}) 98 | else: 99 | keys += mux_key_t.substitute({'key_name' : 'alu_' + str(a2) + '_input_B', 'table_type' : 'ternary'}) 100 | 101 | table_size = 2 ** ((sub_tree * (num_layers + 1)) - sub_tree) 102 | if leaf_limit != 0: 103 | table_size = min(table_size, leaf_limit) 104 | 105 | if transient: 106 | table_size = table_size * 2 107 | 108 | final_table = mux_table_t.substitute({'layer' : num_layers + 1, 'alu' : '1', 'table_size' : int(table_size), 'actions': '\n\t\t\tset_leaf;', 'keys' : keys}) 109 | return final_table 110 | 111 | def leo_tcam_gen(sub_tree, num_layers, num_features, leaf_limit, transient): 112 | num_alus = (2 ** sub_tree) - 1 113 | 114 | layers = [] 115 | for l in range(1, num_layers + 1): 116 | layers += layer_gen(num_alus, num_features, l, sub_tree, leaf_limit, transient) 117 | 118 | final_table = final_table_gen(num_layers, num_alus, sub_tree, leaf_limit, transient) 119 | custom_hdrs = custom_hdrs_gen(num_layers, num_alus, num_features) 120 | apply_block = apply_block_gen(num_layers, num_alus) 121 | 122 | code = [std_headers] + [custom_hdrs] + [ingress_parser_deparser] + [egress_parser_deparser] + layers + [final_table] + [apply_block] + [footer] 123 | return code -------------------------------------------------------------------------------- /leo-generator/leo_templates.py: -------------------------------------------------------------------------------- 1 | from string import Template 2 | 3 | stateless_AND_alu_T = Template(''' 4 | action ALU_${alu}_and() { 5 | hdr.leo.alu_${alu}_result = hdr.leo.alu_${alu}_input & 32768; 6 | } 7 | ''') 8 | 9 | mux_action_decl_with_result_t = Template(''' 10 | action set_${layer}_${alu}_feature${feature}(bit result, bit constraint) { 11 | hdr.leo.layer_${layer_prev}_result = result; 12 | hdr.leo.alu_${alu}_input = hdr.leo.feature_${feature} + constraint; 13 | } 14 | ''') 15 | 16 | mux_action_alt_decl_with_result_t = Template(''' 17 | action set_${layer}_${alu}_feature${feature}(bit result, bit constraint) { 18 | hdr.leo.layer_${layer_prev}_result = result; 19 | hdr.leo.alu_${alu}_input_B = hdr.leo.feature_${feature} + constraint; 20 | } 21 | ''') 22 | 23 | mux_action_decl_t = Template(''' 24 | action set_${layer}_${alu}_feature${feature}(bit constraint) { 25 | hdr.leo.alu_${alu}_input = hdr.leo.feature_${feature} + constraint; 26 | } 27 | ''') 28 | 29 | mux_action_alt_decl_t = Template(''' 30 | action set_${layer}_${alu}_feature${feature}(bit constraint) { 31 | hdr.leo.alu_${alu}_input_B = hdr.leo.feature_${feature} + constraint; 32 | } 33 | ''') 34 | 35 | mux_table_t = Template(''' 36 | table layer_${layer}_${alu} { 37 | key = {${keys} 38 | } 39 | actions = {${actions} 40 | NoAction; 41 | } 42 | size = ${table_size}; 43 | default_action = NoAction(); 44 | } 45 | ''') 46 | 47 | mux_action_t = Template(''' 48 | set_${layer}_${alu}_feature${feature};''') 49 | 50 | mux_key_t = Template(''' 51 | hdr.leo.${key_name} : ${table_type};''') 52 | 53 | custom_header_t = Template(''' 54 | #define FEATURE_WIDTH 16 55 | #define LEAF_ID_WIDTH 16 56 | 57 | header leo_hdr_t { 58 | bit leaf; 59 | bit<1> tree_id; 60 | bit<7> padding; 61 | ${hdrs}\tbit<48> start_time; 62 | bit<48> end_time; 63 | bit<48> backup_time; 64 | } 65 | ''') 66 | 67 | apply_t = Template(''' 68 | apply { 69 | ${layer_apply} 70 | hdr.leo.end_time = eg_intr_from_prsr.global_tstamp; 71 | } 72 | } 73 | ''') 74 | 75 | 76 | egress_parser_deparser = ''' 77 | // --------------------------------------------------------------------------- 78 | // Egress Parser 79 | // --------------------------------------------------------------------------- 80 | parser SwitchEgressParser( 81 | packet_in pkt, 82 | out header_t hdr, 83 | out metadata_t eg_md, 84 | out egress_intrinsic_metadata_t eg_intr_md) { 85 | 86 | state start { 87 | pkt.extract(eg_intr_md); 88 | transition parse_ethernet; 89 | } 90 | 91 | state parse_ethernet { 92 | pkt.extract(hdr.ethernet); 93 | transition select(hdr.ethernet.ether_type) { 94 | ETHERTYPE_IPV4 : parse_ipv4; 95 | default : reject; 96 | } 97 | } 98 | 99 | state parse_ipv4 { 100 | pkt.extract(hdr.ipv4); 101 | transition select(hdr.ipv4.protocol){ 102 | IP_PROTOCOLS_TCP: parse_tcp; 103 | default: reject; 104 | } 105 | } 106 | 107 | state parse_tcp { 108 | pkt.extract(hdr.tcp); 109 | transition parse_class_hdr; 110 | } 111 | 112 | state parse_class_hdr { 113 | pkt.extract(hdr.leo); 114 | transition accept; 115 | } 116 | } 117 | 118 | // --------------------------------------------------------------------------- 119 | // Egress Deparser 120 | // --------------------------------------------------------------------------- 121 | control SwitchEgressDeparser(packet_out pkt, 122 | inout header_t hdr, 123 | in metadata_t eg_md, 124 | in egress_intrinsic_metadata_for_deparser_t 125 | eg_intr_dprsr_md 126 | ) { 127 | 128 | apply { 129 | pkt.emit(hdr.ethernet); 130 | pkt.emit(hdr.ipv4); 131 | pkt.emit(hdr.tcp); 132 | pkt.emit(hdr.leo); 133 | } 134 | } 135 | 136 | // --------------------------------------------------------------------------- 137 | // Egress 138 | // --------------------------------------------------------------------------- 139 | control SwitchEgress( 140 | inout header_t hdr, 141 | inout metadata_t eg_md, 142 | in egress_intrinsic_metadata_t eg_intr_md, 143 | in egress_intrinsic_metadata_from_parser_t eg_intr_from_prsr, 144 | inout egress_intrinsic_metadata_for_deparser_t eg_intr_md_for_dprsr, 145 | inout egress_intrinsic_metadata_for_output_port_t eg_intr_md_for_oport) { 146 | 147 | action set_leaf(bit leaf) { 148 | hdr.leo.leaf = leaf; 149 | } 150 | ''' 151 | 152 | 153 | footer = ''' 154 | Pipeline(SwitchIngressParser(), 155 | SwitchIngress(), 156 | SwitchIngressDeparser(), 157 | SwitchEgressParser(), 158 | SwitchEgress(), 159 | SwitchEgressDeparser()) pipe; 160 | 161 | Switch(pipe) main; 162 | ''' 163 | 164 | std_headers = ''' 165 | #include 166 | #if __TARGET_TOFINO__ == 3 167 | #include 168 | #elif __TARGET_TOFINO__ == 2 169 | #include 170 | #else 171 | #include 172 | #endif 173 | 174 | const bit<16> ETHERTYPE_IPV4 = 16w0x0800; 175 | const bit<8> IP_PROTOCOLS_TCP = 6; 176 | 177 | header ethernet_h { 178 | bit<48> dst_addr; 179 | bit<48> src_addr; 180 | bit<16> ether_type; 181 | } 182 | 183 | header ipv4_h { 184 | bit<4> version; 185 | bit<4> ihl; 186 | bit<8> diffserv; 187 | bit<16> total_len; 188 | bit<16> identification; 189 | bit<3> flags; 190 | bit<13> frag_offset; 191 | bit<8> ttl; 192 | bit<8> protocol; 193 | bit<16> hdr_checksum; 194 | bit<32> src_addr; 195 | bit<32> dst_addr; 196 | } 197 | 198 | header tcp_h { 199 | bit<16> src_port; 200 | bit<16> dst_port; 201 | bit<32> seq_no; 202 | bit<32> ack_no; 203 | bit<4> data_offset; 204 | bit<4> res; 205 | bit<1> cwr; 206 | bit<1> ece; 207 | bit<1> urg; 208 | bit<1> ack; 209 | bit<1> psh; 210 | bit<1> rst; 211 | bit<1> syn; 212 | bit<1> fin; 213 | bit<16> window; 214 | bit<16> checksum; 215 | bit<16> urgent_ptr; 216 | } 217 | ''' 218 | 219 | ingress_parser_deparser = ''' 220 | header resubmit_header_t { 221 | bit<8> type; 222 | bit<8> class_id; 223 | } 224 | 225 | struct header_t { 226 | ethernet_h ethernet; 227 | ipv4_h ipv4; 228 | tcp_h tcp; 229 | leo_hdr_t leo; 230 | } 231 | 232 | const bit<8> RESUB_TYPE = 255; 233 | 234 | struct metadata_t { 235 | bit<8> resub_type; 236 | resubmit_header_t resub_hdr; 237 | } 238 | 239 | typedef bit<9> egressSpec_t; 240 | 241 | // --------------------------------------------------------------------------- 242 | // Ingress parser 243 | // --------------------------------------------------------------------------- 244 | parser SwitchIngressParser( 245 | packet_in pkt, 246 | out header_t hdr, 247 | out metadata_t ig_md, 248 | out ingress_intrinsic_metadata_t ig_intr_md) { 249 | 250 | state start { 251 | pkt.extract(ig_intr_md); 252 | ig_md.resub_type = 0; 253 | transition select(ig_intr_md.resubmit_flag) { 254 | 1 : parse_resubmit; 255 | 0 : parse_port_metadata; 256 | } 257 | } 258 | 259 | state parse_resubmit { 260 | ig_md.resub_type = pkt.lookahead>()[7:0]; 261 | transition select(ig_md.resub_type) { 262 | RESUB_TYPE : parse_resub; 263 | default : reject; 264 | } 265 | } 266 | 267 | state parse_resub { 268 | pkt.extract(ig_md.resub_hdr); 269 | transition parse_resub_end; 270 | } 271 | 272 | state parse_resub_end { 273 | transition parse_ethernet; 274 | } 275 | 276 | state parse_port_metadata { 277 | pkt.advance(PORT_METADATA_SIZE); 278 | transition parse_ethernet; 279 | } 280 | 281 | state parse_ethernet { 282 | pkt.extract(hdr.ethernet); 283 | transition select(hdr.ethernet.ether_type) { 284 | ETHERTYPE_IPV4: parse_ipv4; 285 | default: reject; 286 | } 287 | } 288 | 289 | state parse_ipv4 { 290 | pkt.extract(hdr.ipv4); 291 | transition select(hdr.ipv4.protocol){ 292 | IP_PROTOCOLS_TCP: parse_tcp; 293 | default: reject; 294 | } 295 | } 296 | 297 | state parse_tcp { 298 | pkt.extract(hdr.tcp); 299 | transition parse_class_hdr; 300 | } 301 | 302 | state parse_class_hdr { 303 | pkt.extract(hdr.leo); 304 | transition accept; 305 | } 306 | } 307 | 308 | // --------------------------------------------------------------------------- 309 | // Ingress Deparser 310 | // --------------------------------------------------------------------------- 311 | control SwitchIngressDeparser( 312 | packet_out pkt, 313 | inout header_t hdr, 314 | in metadata_t ig_md, 315 | in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md) { 316 | 317 | Checksum() ipv4_checksum; 318 | 319 | apply { 320 | hdr.ipv4.hdr_checksum = ipv4_checksum.update({ 321 | hdr.ipv4.version, 322 | hdr.ipv4.ihl, 323 | hdr.ipv4.diffserv, 324 | hdr.ipv4.total_len, 325 | hdr.ipv4.identification, 326 | hdr.ipv4.flags, 327 | hdr.ipv4.frag_offset, 328 | hdr.ipv4.ttl, 329 | hdr.ipv4.protocol, 330 | hdr.ipv4.src_addr, 331 | hdr.ipv4.dst_addr}); 332 | 333 | pkt.emit(hdr.ethernet); 334 | pkt.emit(hdr.ipv4); 335 | pkt.emit(hdr.tcp); 336 | pkt.emit(hdr.leo); 337 | } 338 | } 339 | 340 | // --------------------------------------------------------------------------- 341 | // Ingress 342 | // --------------------------------------------------------------------------- 343 | control SwitchIngress( 344 | inout header_t hdr, 345 | inout metadata_t ig_md, 346 | in ingress_intrinsic_metadata_t ig_intr_md, 347 | in ingress_intrinsic_metadata_from_parser_t ig_prsr_md, 348 | inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md, 349 | inout ingress_intrinsic_metadata_for_tm_t ig_tm_md) { 350 | 351 | const PortId_t CPU_PORT = 64; 352 | 353 | action drop() { 354 | ig_dprsr_md.drop_ctl = 1; 355 | } 356 | 357 | action ipv4_forward(egressSpec_t port) { 358 | ig_tm_md.ucast_egress_port = port; 359 | hdr.ipv4.ttl = hdr.ipv4.ttl - 1; 360 | } 361 | 362 | action send_to_cpu() { 363 | ig_tm_md.ucast_egress_port = CPU_PORT; 364 | } 365 | 366 | table ipv4_exact { 367 | key = { 368 | hdr.ipv4.dst_addr: exact; 369 | } 370 | actions = { 371 | ipv4_forward; 372 | send_to_cpu; 373 | drop; 374 | } 375 | size = 10000; 376 | default_action = send_to_cpu(); 377 | } 378 | 379 | action change_active_tree(bit<1> tree_id) { 380 | hdr.leo.tree_id = tree_id; 381 | } 382 | 383 | action default_tree() { 384 | hdr.leo.tree_id = 0; 385 | } 386 | 387 | table tree_id_table { 388 | key = { 389 | hdr.ipv4.src_addr: ternary; 390 | } 391 | actions = { 392 | change_active_tree; 393 | default_tree; 394 | } 395 | size = 1; 396 | default_action = default_tree(); 397 | } 398 | 399 | // Declare stateful features registers here 400 | 401 | apply { 402 | hdr.leo.start_time = ig_intr_md.ingress_mac_tstamp; 403 | tree_id_table.apply(); 404 | 405 | // Execute stateful features registers here 406 | // Populate features to hdr.leo.feature_i here 407 | 408 | if (hdr.ipv4.isValid()) { 409 | ipv4_exact.apply(); 410 | } 411 | } 412 | } 413 | ''' 414 | 415 | clear_table_t = Template('''bfrt.Leo.pipe.SwitchEngress.layer_${layer_id}_${alu}.clear()''') 416 | 417 | add_tcam_entry_layer_1 = Template(''' 418 | bfrt.usman.pipe.SwitchIngress.layer_1_${alu}.add_with_set_1_${alu}_feature${feature}(${tree_id},0xffff,0,${constraint}) 419 | ''') 420 | 421 | add_tcam_entry_with_prev_result_set_only = Template(''' 422 | bfrt.usman.pipe.SwitchIngress.layer_${layer}_${alu}.add_with_set_${layer}_${alu}_feature${feature}(${keys_and_masks},0,${result},${constraint}) 423 | ''') 424 | 425 | add_tcam_entry_with_prev_result_match_and_set = Template(''' 426 | bfrt.usman.pipe.SwitchIngress.layer_${layer}_${alu}.add_with_set_${layer}_${alu}_feature${feature}(${prev_layer_result},0xffff,${keys_and_masks},0,${constraint},${result}) 427 | ''') 428 | 429 | add_tcam_entry_with_prev_result_match_only = Template(''' 430 | bfrt.usman.pipe.SwitchIngress.layer_${layer}_${alu}.add_with_set_${layer}_${alu}_feature${feature}(${prev_layer_result},0xffff,${keys_and_masks},0,${constraint}) 431 | ''') 432 | 433 | add_tcam_entry_with_leaf = Template(''' 434 | bfrt.usman.pipe.SwitchIngress.layer_${layer}_${alu}.add_with_set_${layer}_${alu}_feature${feature}(${prev_layer_result},0xffff,${keys_and_masks},0,${constraint}) 435 | ''') -------------------------------------------------------------------------------- /leo/feature-budget-finder.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | NUM_FEATURES = 9 3 | BITS_BUDGET = 57 4 | 5 | print('NUM FEATURES =', NUM_FEATURES, '| BITS BUDGET =', BITS_BUDGET) 6 | print('---') 7 | 8 | for i in range(NUM_FEATURES, -1, -1): 9 | max_use = 0 10 | max_config = None 11 | for j in range(0, NUM_FEATURES + 1): 12 | bits_used = (16 * i) + (8 * j) 13 | if i + j <= NUM_FEATURES: 14 | if bits_used <= BITS_BUDGET: 15 | if bits_used > max_use: 16 | max_use = bits_used 17 | max_config = (i, j) 18 | if max_use: 19 | print('16-bit x', max_config[0], '| 8-bit x ', max_config[1], '| Use =', max_use, '/', BITS_BUDGET) 20 | 21 | if __name__ == '__main__': 22 | main() -------------------------------------------------------------------------------- /leo/leo-1m-flows.p4: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #if __TARGET_TOFINO__ == 3 4 | #include 5 | #elif __TARGET_TOFINO__ == 2 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | const bit<8> FWD_PORT = 5; 12 | const bit<8> BWD_PORT = 7; 13 | 14 | 15 | #define KEY_SIZE 20 16 | #define FEATURE_WIDTH 16 17 | #define FEATURE_WIDTH_8 8 18 | #define NUM_REGISTERS 188416 19 | #define NUM_REGISTERS_8 376832 20 | #define NUM_REGISTERS_ONE_STAGE 114688 21 | #define NUM_REGISTERS_65K 65536 22 | #define LEAF_ID_WIDTH 16 23 | 24 | header leo_h { 25 | bit<8> state_group; 26 | bit state_index; 27 | bit<12> padding; 28 | bit<8> ingress_port; 29 | bit<8> pkt_len_div64; 30 | bit feature_1; 31 | bit feature_2; 32 | bit feature_3; 33 | bit feature_4; 34 | bit feature_5; 35 | bit alu_1_input; 36 | bit alu_1_input_B; 37 | bit alu_2_input; 38 | bit alu_2_input_B; 39 | bit alu_3_input; 40 | bit alu_3_input_B; 41 | bit leaf; 42 | bit layer_1_result; 43 | bit layer_2_result; 44 | bit layer_3_result; 45 | bit layer_4_result; 46 | } 47 | 48 | typedef bit<48> mac_addr_t; 49 | typedef bit<32> ipv4_addr_t; 50 | typedef bit<16> ether_type_t; 51 | typedef bit<8> ip_protocol_t; 52 | 53 | const ether_type_t ETHERTYPE_IPV4 = 16w0x0800; 54 | const ip_protocol_t IP_PROTOCOLS_TCP = 6; 55 | 56 | // 14 byte 57 | header ethernet_h { 58 | mac_addr_t dst_addr; 59 | mac_addr_t src_addr; 60 | ether_type_t ether_type; 61 | } 62 | 63 | // 20 byte 64 | header ipv4_h { 65 | bit<4> version; 66 | bit<4> ihl; 67 | bit<8> diffserv; 68 | bit<16> total_len; 69 | bit<16> identification; 70 | bit<3> flags; 71 | bit<13> frag_offset; 72 | bit<8> ttl; 73 | ip_protocol_t protocol; 74 | bit<16> hdr_checksum; 75 | ipv4_addr_t src_addr; 76 | ipv4_addr_t dst_addr; 77 | } 78 | 79 | // 20 byte 80 | header tcp_h { 81 | bit<16> src_port; 82 | bit<16> dst_port; 83 | bit<32> seq_no; 84 | bit<32> ack_no; 85 | bit<4> data_offset; 86 | bit<4> res; 87 | bit<1> cwr; 88 | bit<1> ece; 89 | bit<1> urg; 90 | bit<1> ack; 91 | bit<1> psh; 92 | bit<1> rst; 93 | bit<1> syn; 94 | bit<1> fin; 95 | bit<16> window; 96 | bit<16> checksum; 97 | bit<16> urgent_ptr; 98 | } 99 | 100 | header resubmit_header_t { 101 | bit<8> type; 102 | bit<8> leo_class_id; 103 | } 104 | 105 | struct header_t { 106 | ethernet_h ethernet; 107 | ipv4_h ipv4; 108 | tcp_h tcp; 109 | leo_h leo; 110 | } 111 | 112 | #include "tofino-util.p4" 113 | 114 | const bit<8> RESUB_TYPE = 255; 115 | 116 | struct metadata_t { 117 | bit<8> resub_type; 118 | resubmit_header_t resub_hdr; 119 | } 120 | 121 | typedef bit<9> egressSpec_t; 122 | 123 | // --------------------------------------------------------------------------- 124 | // Ingress parser 125 | // --------------------------------------------------------------------------- 126 | parser SwitchIngressParser( 127 | packet_in pkt, 128 | out header_t hdr, 129 | out metadata_t ig_md, 130 | out ingress_intrinsic_metadata_t ig_intr_md) { 131 | 132 | state start { 133 | pkt.extract(ig_intr_md); 134 | ig_md.resub_type = 0; 135 | transition select(ig_intr_md.resubmit_flag) { 136 | 1 : parse_resubmit; 137 | 0 : parse_port_metadata; 138 | } 139 | } 140 | 141 | state parse_resubmit { 142 | ig_md.resub_type = pkt.lookahead>()[7:0]; 143 | transition select(ig_md.resub_type) { 144 | RESUB_TYPE : parse_resub; 145 | default : reject; 146 | } 147 | } 148 | 149 | state parse_resub { 150 | pkt.extract(ig_md.resub_hdr); 151 | transition parse_resub_end; 152 | } 153 | 154 | state parse_resub_end { 155 | transition parse_ethernet; 156 | } 157 | 158 | state parse_port_metadata { 159 | pkt.advance(PORT_METADATA_SIZE); 160 | transition parse_ethernet; 161 | } 162 | 163 | state parse_ethernet { 164 | pkt.extract(hdr.ethernet); 165 | transition select(hdr.ethernet.ether_type) { 166 | ETHERTYPE_IPV4: parse_ipv4; 167 | default: reject; 168 | } 169 | } 170 | 171 | state parse_ipv4 { 172 | pkt.extract(hdr.ipv4); 173 | transition select(hdr.ipv4.protocol){ 174 | IP_PROTOCOLS_TCP: parse_tcp; 175 | default: reject; 176 | } 177 | } 178 | 179 | state parse_tcp { 180 | pkt.extract(hdr.tcp); 181 | transition parse_leo_hdr; 182 | } 183 | 184 | state parse_leo_hdr { 185 | pkt.extract(hdr.leo); 186 | transition accept; 187 | } 188 | } 189 | 190 | // --------------------------------------------------------------------------- 191 | // Ingress Deparser 192 | // --------------------------------------------------------------------------- 193 | 194 | control SwitchIngressDeparser( 195 | packet_out pkt, 196 | inout header_t hdr, 197 | in metadata_t ig_md, 198 | in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md) { 199 | 200 | Checksum() ipv4_checksum; 201 | 202 | apply { 203 | hdr.ipv4.hdr_checksum = ipv4_checksum.update({ 204 | hdr.ipv4.version, 205 | hdr.ipv4.ihl, 206 | hdr.ipv4.diffserv, 207 | hdr.ipv4.total_len, 208 | hdr.ipv4.identification, 209 | hdr.ipv4.flags, 210 | hdr.ipv4.frag_offset, 211 | hdr.ipv4.ttl, 212 | hdr.ipv4.protocol, 213 | hdr.ipv4.src_addr, 214 | hdr.ipv4.dst_addr}); 215 | 216 | pkt.emit(hdr.ethernet); 217 | pkt.emit(hdr.ipv4); 218 | pkt.emit(hdr.tcp); 219 | pkt.emit(hdr.leo); 220 | } 221 | } 222 | 223 | // --------------------------------------------------------------------------- 224 | // Ingress 225 | // --------------------------------------------------------------------------- 226 | control SwitchIngress( 227 | inout header_t hdr, 228 | inout metadata_t ig_md, 229 | in ingress_intrinsic_metadata_t ig_intr_md, 230 | in ingress_intrinsic_metadata_from_parser_t ig_prsr_md, 231 | inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md, 232 | inout ingress_intrinsic_metadata_for_tm_t ig_tm_md) { 233 | 234 | const PortId_t CPU_PORT = 64; 235 | 236 | action drop() { 237 | ig_dprsr_md.drop_ctl = 1; 238 | } 239 | 240 | action ipv4_forward(egressSpec_t port) { 241 | ig_tm_md.ucast_egress_port = port; 242 | hdr.ipv4.ttl = hdr.ipv4.ttl - 1; 243 | } 244 | 245 | action send_to_cpu() { 246 | ig_tm_md.ucast_egress_port = CPU_PORT; 247 | } 248 | 249 | table ipv4_exact { 250 | key = { 251 | hdr.ipv4.dst_addr: exact; 252 | } 253 | actions = { 254 | ipv4_forward; 255 | send_to_cpu; 256 | drop; 257 | } 258 | size = 10000; 259 | default_action = send_to_cpu(); 260 | } 261 | 262 | Hash>(HashAlgorithm_t.CRC32) crc32; 263 | 264 | action hash_packet(ipv4_addr_t ipAddr1, ipv4_addr_t ipAddr2, bit<16> port1, bit<16> port2, bit<8> proto) { 265 | hdr.leo.state_index = crc32.get({ipAddr1, 266 | ipAddr2, 267 | port1, 268 | port2, 269 | proto}); 270 | } 271 | 272 | action set_state_group_0() { 273 | hdr.leo.state_group = 0; 274 | } 275 | 276 | action set_state_group_1_16bit() { 277 | hdr.leo.state_group = 1; 278 | hdr.leo.state_index = hdr.leo.state_index - 188416; 279 | } 280 | 281 | action set_state_group_1_8bit() { 282 | hdr.leo.state_group = 1; 283 | hdr.leo.state_index = hdr.leo.state_index - 376832; 284 | } 285 | 286 | action set_state_group_2_16bit() { 287 | hdr.leo.state_group = 2; 288 | hdr.leo.state_index = hdr.leo.state_index - 376832; 289 | } 290 | 291 | action set_state_group_2_8bit() { 292 | hdr.leo.state_group = 2; 293 | hdr.leo.state_index = hdr.leo.state_index - 565248; 294 | } 295 | 296 | action set_state_group_3_16bit() { 297 | hdr.leo.state_group = 3; 298 | hdr.leo.state_index = hdr.leo.state_index - 565248; 299 | } 300 | 301 | action set_state_group_3_8bit() { 302 | hdr.leo.state_group = 3; 303 | hdr.leo.state_index = hdr.leo.state_index - 753664; 304 | } 305 | 306 | table state_group_decider { 307 | key = { 308 | hdr.leo.state_index : range; 309 | } 310 | actions = { 311 | set_state_group_0; 312 | set_state_group_1_16bit; 313 | set_state_group_1_8bit; 314 | set_state_group_2_16bit; 315 | set_state_group_2_8bit; 316 | set_state_group_3_16bit; 317 | set_state_group_3_8bit; 318 | NoAction; 319 | } 320 | size = 1000; 321 | default_action = NoAction(); 322 | } 323 | 324 | Register, bit>(NUM_REGISTERS_8) bwd_packet_length_min; 325 | RegisterAction, bit, bit>(bwd_packet_length_min) bwd_packet_length_min_update = { 326 | void apply(inout bit value, out bit read_value){ 327 | if (hdr.leo.ingress_port == BWD_PORT) { 328 | if (hdr.leo.pkt_len_div64 < value) { 329 | value = hdr.leo.pkt_len_div64; 330 | } 331 | } 332 | read_value = 8w0 ++ value; 333 | } 334 | }; 335 | 336 | Register, bit>(NUM_REGISTERS_8) fwd_segment_size_min; 337 | RegisterAction, bit, bit>(fwd_segment_size_min) fwd_segment_size_min_update = { 338 | void apply(inout bit value, out bit read_value){ 339 | if (hdr.leo.ingress_port == FWD_PORT) { 340 | if ((hdr.leo.pkt_len_div64 - 54) < value) { 341 | value = hdr.leo.pkt_len_div64 - 54; 342 | } 343 | } 344 | read_value = 8w0 ++ value; 345 | } 346 | }; 347 | 348 | Register, bit>(NUM_REGISTERS) bwd_flow_size; 349 | RegisterAction, bit, bit>(bwd_flow_size) bwd_flow_size_update = { 350 | void apply(inout bit value, out bit read_value){ 351 | if (hdr.leo.ingress_port == BWD_PORT) { 352 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 353 | } 354 | read_value = value; 355 | } 356 | }; 357 | 358 | Register, bit>(NUM_REGISTERS) fwd_flow_size; 359 | RegisterAction, bit, bit>(fwd_flow_size) fwd_flow_size_update = { 360 | void apply(inout bit value, out bit read_value){ 361 | if (hdr.leo.ingress_port == FWD_PORT) { 362 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 363 | } 364 | read_value = value; 365 | } 366 | }; 367 | 368 | Register, bit>(NUM_REGISTERS) bwd_flow_size_B; 369 | RegisterAction, bit, bit>(bwd_flow_size_B) bwd_flow_size_B_update = { 370 | void apply(inout bit value, out bit read_value){ 371 | if (hdr.leo.ingress_port == BWD_PORT) { 372 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 373 | } 374 | read_value = value; 375 | } 376 | }; 377 | 378 | Register, bit>(NUM_REGISTERS) fwd_flow_size_B; 379 | RegisterAction, bit, bit>(fwd_flow_size_B) fwd_flow_size_B_update = { 380 | void apply(inout bit value, out bit read_value){ 381 | if (hdr.leo.ingress_port == FWD_PORT) { 382 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 383 | } 384 | read_value = value; 385 | } 386 | }; 387 | 388 | Register, bit>(NUM_REGISTERS_ONE_STAGE) bwd_packet_length_min_C; 389 | RegisterAction, bit, bit>(bwd_packet_length_min_C) bwd_packet_length_min_C_update = { 390 | void apply(inout bit value, out bit read_value){ 391 | if (hdr.leo.ingress_port == BWD_PORT) { 392 | if (hdr.leo.pkt_len_div64 < value) { 393 | value = hdr.leo.pkt_len_div64; 394 | } 395 | } 396 | read_value = 8w0 ++ value; 397 | } 398 | }; 399 | 400 | Register, bit>(NUM_REGISTERS_ONE_STAGE) fwd_segment_size_min_C; 401 | RegisterAction, bit, bit>(fwd_segment_size_min_C) fwd_segment_size_min_C_update = { 402 | void apply(inout bit value, out bit read_value){ 403 | if (hdr.leo.ingress_port == FWD_PORT) { 404 | if ((hdr.leo.pkt_len_div64 - 54) < value) { 405 | value = hdr.leo.pkt_len_div64 - 54; 406 | } 407 | } 408 | read_value = 8w0 ++ value; 409 | } 410 | }; 411 | 412 | Register, bit>(NUM_REGISTERS_ONE_STAGE) bwd_flow_size_C; 413 | RegisterAction, bit, bit>(bwd_flow_size_C) bwd_flow_size_C_update = { 414 | void apply(inout bit value, out bit read_value){ 415 | if (hdr.leo.ingress_port == BWD_PORT) { 416 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 417 | } 418 | read_value = value; 419 | } 420 | }; 421 | 422 | Register, bit>(NUM_REGISTERS_ONE_STAGE) fwd_flow_size_C; 423 | RegisterAction, bit, bit>(fwd_flow_size_C) fwd_flow_size_C_update = { 424 | void apply(inout bit value, out bit read_value){ 425 | if (hdr.leo.ingress_port == FWD_PORT) { 426 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 427 | } 428 | read_value = value; 429 | } 430 | }; 431 | 432 | Register, bit>(NUM_REGISTERS_8) bwd_packet_length_min_D; 433 | RegisterAction, bit, bit>(bwd_packet_length_min_D) bwd_packet_length_min_D_update = { 434 | void apply(inout bit value, out bit read_value){ 435 | if (hdr.leo.ingress_port == BWD_PORT) { 436 | if (hdr.leo.pkt_len_div64 < value) { 437 | value = hdr.leo.pkt_len_div64; 438 | } 439 | } 440 | read_value = 8w0 ++ value; 441 | } 442 | }; 443 | 444 | Register, bit>(NUM_REGISTERS_8) fwd_segment_size_min_D; 445 | RegisterAction, bit, bit>(fwd_segment_size_min_D) fwd_segment_size_min_D_update = { 446 | void apply(inout bit value, out bit read_value){ 447 | if (hdr.leo.ingress_port == FWD_PORT) { 448 | if ((hdr.leo.pkt_len_div64 - 54) < value) { 449 | value = hdr.leo.pkt_len_div64 - 54; 450 | } 451 | } 452 | read_value = 8w0 ++ value; 453 | } 454 | }; 455 | 456 | Register, bit>(NUM_REGISTERS) bwd_flow_size_D; 457 | RegisterAction, bit, bit>(bwd_flow_size_D) bwd_flow_size_D_update = { 458 | void apply(inout bit value, out bit read_value){ 459 | if (hdr.leo.ingress_port == BWD_PORT) { 460 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 461 | } 462 | read_value = value; 463 | } 464 | }; 465 | 466 | Register, bit>(NUM_REGISTERS) fwd_flow_size_D; 467 | RegisterAction, bit, bit>(fwd_flow_size_D) fwd_flow_size_D_update = { 468 | void apply(inout bit value, out bit read_value){ 469 | if (hdr.leo.ingress_port == FWD_PORT) { 470 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 471 | } 472 | read_value = value; 473 | } 474 | }; 475 | 476 | Register, bit>(NUM_REGISTERS) bwd_flow_size_E; 477 | RegisterAction, bit, bit>(bwd_flow_size_E) bwd_flow_size_E_update = { 478 | void apply(inout bit value, out bit read_value){ 479 | if (hdr.leo.ingress_port == BWD_PORT) { 480 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 481 | } 482 | read_value = value; 483 | } 484 | }; 485 | 486 | Register, bit>(NUM_REGISTERS) fwd_flow_size_E; 487 | RegisterAction, bit, bit>(fwd_flow_size_E) fwd_flow_size_E_update = { 488 | void apply(inout bit value, out bit read_value){ 489 | if (hdr.leo.ingress_port == FWD_PORT) { 490 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 491 | } 492 | read_value = value; 493 | } 494 | }; 495 | 496 | Register, bit>(NUM_REGISTERS_ONE_STAGE) bwd_packet_length_min_F; 497 | RegisterAction, bit, bit>(bwd_packet_length_min_F) bwd_packet_length_min_F_update = { 498 | void apply(inout bit value, out bit read_value){ 499 | if (hdr.leo.ingress_port == BWD_PORT) { 500 | if (hdr.leo.pkt_len_div64 < value) { 501 | value = hdr.leo.pkt_len_div64; 502 | } 503 | } 504 | read_value = 8w0 ++ value; 505 | } 506 | }; 507 | 508 | Register, bit>(NUM_REGISTERS_ONE_STAGE) fwd_segment_size_min_F; 509 | RegisterAction, bit, bit>(fwd_segment_size_min_F) fwd_segment_size_min_F_update = { 510 | void apply(inout bit value, out bit read_value){ 511 | if (hdr.leo.ingress_port == FWD_PORT) { 512 | if ((hdr.leo.pkt_len_div64 - 54) < value) { 513 | value = hdr.leo.pkt_len_div64 - 54; 514 | } 515 | } 516 | read_value = 8w0 ++ value; 517 | } 518 | }; 519 | 520 | Register, bit>(NUM_REGISTERS_ONE_STAGE) bwd_flow_size_F; 521 | RegisterAction, bit, bit>(bwd_flow_size_F) bwd_flow_size_F_update = { 522 | void apply(inout bit value, out bit read_value){ 523 | if (hdr.leo.ingress_port == BWD_PORT) { 524 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 525 | } 526 | read_value = value; 527 | } 528 | }; 529 | 530 | Register, bit>(NUM_REGISTERS_ONE_STAGE) fwd_flow_size_F; 531 | RegisterAction, bit, bit>(fwd_flow_size_F) fwd_flow_size_F_update = { 532 | void apply(inout bit value, out bit read_value){ 533 | if (hdr.leo.ingress_port == FWD_PORT) { 534 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 535 | } 536 | read_value = value; 537 | } 538 | }; 539 | 540 | Register, bit>(NUM_REGISTERS_65K) bwd_packet_length_min_G; 541 | RegisterAction, bit, bit>(bwd_packet_length_min_G) bwd_packet_length_min_G_update = { 542 | void apply(inout bit value, out bit read_value){ 543 | if (hdr.leo.ingress_port == BWD_PORT) { 544 | if (hdr.leo.pkt_len_div64 < value) { 545 | value = hdr.leo.pkt_len_div64; 546 | } 547 | } 548 | read_value = 8w0 ++ value; 549 | } 550 | }; 551 | 552 | Register, bit>(NUM_REGISTERS_65K) fwd_segment_size_min_G; 553 | RegisterAction, bit, bit>(fwd_segment_size_min_G) fwd_segment_size_min_G_update = { 554 | void apply(inout bit value, out bit read_value){ 555 | if (hdr.leo.ingress_port == FWD_PORT) { 556 | if ((hdr.leo.pkt_len_div64 - 54) < value) { 557 | value = hdr.leo.pkt_len_div64 - 54; 558 | } 559 | } 560 | read_value = 8w0 ++ value; 561 | } 562 | }; 563 | 564 | Register, bit>(NUM_REGISTERS_65K) bwd_flow_size_G; 565 | RegisterAction, bit, bit>(bwd_flow_size_G) bwd_flow_size_G_update = { 566 | void apply(inout bit value, out bit read_value){ 567 | if (hdr.leo.ingress_port == BWD_PORT) { 568 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 569 | } 570 | read_value = value; 571 | } 572 | }; 573 | 574 | Register, bit>(NUM_REGISTERS_65K) fwd_flow_size_G; 575 | RegisterAction, bit, bit>(fwd_flow_size_G) fwd_flow_size_G_update = { 576 | void apply(inout bit value, out bit read_value){ 577 | if (hdr.leo.ingress_port == FWD_PORT) { 578 | value = value + (8w0 ++ hdr.leo.pkt_len_div64); 579 | } 580 | read_value = value; 581 | } 582 | }; 583 | 584 | apply { 585 | if (hdr.ipv4.isValid()) { 586 | ipv4_exact.apply(); 587 | } 588 | 589 | hdr.leo.pkt_len_div64 = (hdr.ipv4.total_len >> 6)[7:0]; 590 | hdr.leo.ingress_port = ig_intr_md.ingress_port[7:0]; 591 | hdr.leo.feature_5 = hdr.tcp.dst_port; 592 | 593 | hash_packet(hdr.ipv4.src_addr, hdr.ipv4.dst_addr, hdr.tcp.src_port, hdr.tcp.dst_port, hdr.ipv4.protocol); 594 | state_group_decider.apply(); 595 | 596 | if (hdr.leo.state_group == 0) { 597 | hdr.leo.feature_1 = bwd_packet_length_min_update.execute(hdr.leo.state_index); 598 | hdr.leo.feature_2 = fwd_segment_size_min_update.execute(hdr.leo.state_index); 599 | hdr.leo.feature_3 = bwd_flow_size_update.execute(hdr.leo.state_index); 600 | hdr.leo.feature_4 = fwd_flow_size_update.execute(hdr.leo.state_index); 601 | } else if (hdr.leo.state_group == 1) { 602 | hdr.leo.feature_3 = bwd_flow_size_B_update.execute(hdr.leo.state_index); 603 | hdr.leo.feature_4 = fwd_flow_size_B_update.execute(hdr.leo.state_index); 604 | } else if (hdr.leo.state_group == 2) { 605 | hdr.leo.feature_1 = bwd_packet_length_min_C_update.execute(hdr.leo.state_index); 606 | hdr.leo.feature_2 = fwd_segment_size_min_C_update.execute(hdr.leo.state_index); 607 | hdr.leo.feature_3 = bwd_flow_size_C_update.execute(hdr.leo.state_index); 608 | hdr.leo.feature_4 = fwd_flow_size_C_update.execute(hdr.leo.state_index); 609 | } else if (hdr.leo.state_group == 3) { 610 | hdr.leo.feature_1 = bwd_packet_length_min_D_update.execute(hdr.leo.state_index); 611 | hdr.leo.feature_2 = fwd_segment_size_min_D_update.execute(hdr.leo.state_index); 612 | hdr.leo.feature_3 = bwd_flow_size_D_update.execute(hdr.leo.state_index); 613 | hdr.leo.feature_4 = fwd_flow_size_D_update.execute(hdr.leo.state_index); 614 | } else if (hdr.leo.state_group == 4) { 615 | hdr.leo.feature_3 = bwd_flow_size_E_update.execute(hdr.leo.state_index); 616 | hdr.leo.feature_4 = fwd_flow_size_E_update.execute(hdr.leo.state_index); 617 | } else if (hdr.leo.state_group == 5) { 618 | hdr.leo.feature_1 = bwd_packet_length_min_F_update.execute(hdr.leo.state_index); 619 | hdr.leo.feature_2 = fwd_segment_size_min_F_update.execute(hdr.leo.state_index); 620 | hdr.leo.feature_3 = bwd_flow_size_F_update.execute(hdr.leo.state_index); 621 | hdr.leo.feature_4 = fwd_flow_size_F_update.execute(hdr.leo.state_index); 622 | } else if (hdr.leo.state_group == 6) { 623 | hdr.leo.feature_1 = bwd_packet_length_min_G_update.execute(hdr.leo.state_index); 624 | hdr.leo.feature_2 = fwd_segment_size_min_G_update.execute(hdr.leo.state_index); 625 | hdr.leo.feature_3 = bwd_flow_size_G_update.execute(hdr.leo.state_index); 626 | hdr.leo.feature_4 = fwd_flow_size_G_update.execute(hdr.leo.state_index); 627 | } 628 | } 629 | } 630 | 631 | // --------------------------------------------------------------------------- 632 | // Egress Parser 633 | // --------------------------------------------------------------------------- 634 | parser SwitchEgressParser( 635 | packet_in pkt, 636 | out header_t hdr, 637 | out metadata_t eg_md, 638 | out egress_intrinsic_metadata_t eg_intr_md) { 639 | 640 | TofinoEgressParser() tofino_parser; 641 | 642 | state start { 643 | tofino_parser.apply(pkt, eg_intr_md); 644 | transition parse_ethernet; 645 | } 646 | 647 | state parse_ethernet { 648 | pkt.extract(hdr.ethernet); 649 | transition select(hdr.ethernet.ether_type) { 650 | ETHERTYPE_IPV4 : parse_ipv4; 651 | default : reject; 652 | } 653 | } 654 | 655 | state parse_ipv4 { 656 | pkt.extract(hdr.ipv4); 657 | transition select(hdr.ipv4.protocol){ 658 | IP_PROTOCOLS_TCP: parse_tcp; 659 | default: reject; 660 | } 661 | } 662 | 663 | state parse_tcp { 664 | pkt.extract(hdr.tcp); 665 | transition parse_leo_hdr; 666 | } 667 | 668 | state parse_leo_hdr { 669 | pkt.extract(hdr.leo); 670 | transition accept; 671 | } 672 | } 673 | 674 | 675 | // --------------------------------------------------------------------------- 676 | // Egress 677 | // --------------------------------------------------------------------------- 678 | control SwitchEgress( 679 | inout header_t hdr, 680 | inout metadata_t eg_md, 681 | in egress_intrinsic_metadata_t eg_intr_md, 682 | in egress_intrinsic_metadata_from_parser_t eg_intr_from_prsr, 683 | inout egress_intrinsic_metadata_for_deparser_t eg_intr_md_for_dprsr, 684 | inout egress_intrinsic_metadata_for_output_port_t eg_intr_md_for_oport) { 685 | 686 | action set_leaf(bit leaf) { 687 | hdr.leo.leaf = leaf; 688 | } 689 | 690 | action set_1_1_feature1(bit constraint) { 691 | hdr.leo.alu_1_input = hdr.leo.feature_1 + constraint; 692 | } 693 | 694 | action set_1_1_feature2(bit constraint) { 695 | hdr.leo.alu_1_input = hdr.leo.feature_2 + constraint; 696 | } 697 | 698 | action set_1_1_feature3(bit constraint) { 699 | hdr.leo.alu_1_input = hdr.leo.feature_3 + constraint; 700 | } 701 | 702 | action set_1_1_feature4(bit constraint) { 703 | hdr.leo.alu_1_input = hdr.leo.feature_4 + constraint; 704 | } 705 | 706 | action set_1_1_feature5(bit constraint) { 707 | hdr.leo.alu_1_input = hdr.leo.feature_5 + constraint; 708 | } 709 | 710 | table layer_1_1 { 711 | key = { 712 | hdr.ipv4.version : ternary; 713 | } 714 | actions = { 715 | set_1_1_feature1; 716 | set_1_1_feature2; 717 | set_1_1_feature3; 718 | set_1_1_feature4; 719 | set_1_1_feature5; 720 | NoAction; 721 | } 722 | size = 1; 723 | default_action = NoAction(); 724 | } 725 | 726 | action set_1_2_feature1(bit constraint) { 727 | hdr.leo.alu_2_input = hdr.leo.feature_1 + constraint; 728 | } 729 | 730 | action set_1_2_feature2(bit constraint) { 731 | hdr.leo.alu_2_input = hdr.leo.feature_2 + constraint; 732 | } 733 | 734 | action set_1_2_feature3(bit constraint) { 735 | hdr.leo.alu_2_input = hdr.leo.feature_3 + constraint; 736 | } 737 | 738 | action set_1_2_feature4(bit constraint) { 739 | hdr.leo.alu_2_input = hdr.leo.feature_4 + constraint; 740 | } 741 | 742 | action set_1_2_feature5(bit constraint) { 743 | hdr.leo.alu_2_input = hdr.leo.feature_5 + constraint; 744 | } 745 | 746 | table layer_1_2 { 747 | key = { 748 | hdr.ipv4.version : ternary; 749 | } 750 | actions = { 751 | set_1_2_feature1; 752 | set_1_2_feature2; 753 | set_1_2_feature3; 754 | set_1_2_feature4; 755 | set_1_2_feature5; 756 | NoAction; 757 | } 758 | size = 1; 759 | default_action = NoAction(); 760 | } 761 | 762 | action set_1_3_feature1(bit constraint) { 763 | hdr.leo.alu_3_input = hdr.leo.feature_1 + constraint; 764 | } 765 | 766 | action set_1_3_feature2(bit constraint) { 767 | hdr.leo.alu_3_input = hdr.leo.feature_2 + constraint; 768 | } 769 | 770 | action set_1_3_feature3(bit constraint) { 771 | hdr.leo.alu_3_input = hdr.leo.feature_3 + constraint; 772 | } 773 | 774 | action set_1_3_feature4(bit constraint) { 775 | hdr.leo.alu_3_input = hdr.leo.feature_4 + constraint; 776 | } 777 | 778 | action set_1_3_feature5(bit constraint) { 779 | hdr.leo.alu_3_input = hdr.leo.feature_5 + constraint; 780 | } 781 | 782 | table layer_1_3 { 783 | key = { 784 | hdr.ipv4.version : ternary; 785 | } 786 | actions = { 787 | set_1_3_feature1; 788 | set_1_3_feature2; 789 | set_1_3_feature3; 790 | set_1_3_feature4; 791 | set_1_3_feature5; 792 | NoAction; 793 | } 794 | size = 1; 795 | default_action = NoAction(); 796 | } 797 | 798 | action set_2_1_feature1(bit result, bit constraint) { 799 | hdr.leo.layer_1_result = result; 800 | hdr.leo.alu_1_input_B = hdr.leo.feature_1 + constraint; 801 | } 802 | 803 | action set_2_1_feature2(bit result, bit constraint) { 804 | hdr.leo.layer_1_result = result; 805 | hdr.leo.alu_1_input_B = hdr.leo.feature_2 + constraint; 806 | } 807 | 808 | action set_2_1_feature3(bit result, bit constraint) { 809 | hdr.leo.layer_1_result = result; 810 | hdr.leo.alu_1_input_B = hdr.leo.feature_3 + constraint; 811 | } 812 | 813 | action set_2_1_feature4(bit result, bit constraint) { 814 | hdr.leo.layer_1_result = result; 815 | hdr.leo.alu_1_input_B = hdr.leo.feature_4 + constraint; 816 | } 817 | 818 | action set_2_1_feature5(bit result, bit constraint) { 819 | hdr.leo.layer_1_result = result; 820 | hdr.leo.alu_1_input_B = hdr.leo.feature_5 + constraint; 821 | } 822 | 823 | table layer_2_1 { 824 | key = { 825 | hdr.leo.alu_1_input : ternary; 826 | hdr.leo.alu_2_input : ternary; 827 | hdr.leo.alu_3_input : ternary; 828 | } 829 | actions = { 830 | set_leaf; 831 | set_2_1_feature1; 832 | set_2_1_feature2; 833 | set_2_1_feature3; 834 | set_2_1_feature4; 835 | set_2_1_feature5; 836 | NoAction; 837 | } 838 | size = 4; 839 | default_action = NoAction(); 840 | } 841 | 842 | action set_2_2_feature1(bit constraint) { 843 | hdr.leo.alu_2_input_B = hdr.leo.feature_1 + constraint; 844 | } 845 | 846 | action set_2_2_feature2(bit constraint) { 847 | hdr.leo.alu_2_input_B = hdr.leo.feature_2 + constraint; 848 | } 849 | 850 | action set_2_2_feature3(bit constraint) { 851 | hdr.leo.alu_2_input_B = hdr.leo.feature_3 + constraint; 852 | } 853 | 854 | action set_2_2_feature4(bit constraint) { 855 | hdr.leo.alu_2_input_B = hdr.leo.feature_4 + constraint; 856 | } 857 | 858 | action set_2_2_feature5(bit constraint) { 859 | hdr.leo.alu_2_input_B = hdr.leo.feature_5 + constraint; 860 | } 861 | 862 | table layer_2_2 { 863 | key = { 864 | hdr.leo.alu_1_input : ternary; 865 | hdr.leo.alu_2_input : ternary; 866 | hdr.leo.alu_3_input : ternary; 867 | } 868 | actions = { 869 | set_2_2_feature1; 870 | set_2_2_feature2; 871 | set_2_2_feature3; 872 | set_2_2_feature4; 873 | set_2_2_feature5; 874 | NoAction; 875 | } 876 | size = 4; 877 | default_action = NoAction(); 878 | } 879 | 880 | action set_2_3_feature1(bit constraint) { 881 | hdr.leo.alu_3_input_B = hdr.leo.feature_1 + constraint; 882 | } 883 | 884 | action set_2_3_feature2(bit constraint) { 885 | hdr.leo.alu_3_input_B = hdr.leo.feature_2 + constraint; 886 | } 887 | 888 | action set_2_3_feature3(bit constraint) { 889 | hdr.leo.alu_3_input_B = hdr.leo.feature_3 + constraint; 890 | } 891 | 892 | action set_2_3_feature4(bit constraint) { 893 | hdr.leo.alu_3_input_B = hdr.leo.feature_4 + constraint; 894 | } 895 | 896 | action set_2_3_feature5(bit constraint) { 897 | hdr.leo.alu_3_input_B = hdr.leo.feature_5 + constraint; 898 | } 899 | 900 | table layer_2_3 { 901 | key = { 902 | hdr.leo.alu_1_input : ternary; 903 | hdr.leo.alu_2_input : ternary; 904 | hdr.leo.alu_3_input : ternary; 905 | } 906 | actions = { 907 | set_2_3_feature1; 908 | set_2_3_feature2; 909 | set_2_3_feature3; 910 | set_2_3_feature4; 911 | set_2_3_feature5; 912 | NoAction; 913 | } 914 | size = 4; 915 | default_action = NoAction(); 916 | } 917 | 918 | action set_3_1_feature1(bit result, bit constraint) { 919 | hdr.leo.layer_2_result = result; 920 | hdr.leo.alu_1_input = hdr.leo.feature_1 + constraint; 921 | } 922 | 923 | action set_3_1_feature2(bit result, bit constraint) { 924 | hdr.leo.layer_2_result = result; 925 | hdr.leo.alu_1_input = hdr.leo.feature_2 + constraint; 926 | } 927 | 928 | action set_3_1_feature3(bit result, bit constraint) { 929 | hdr.leo.layer_2_result = result; 930 | hdr.leo.alu_1_input = hdr.leo.feature_3 + constraint; 931 | } 932 | 933 | action set_3_1_feature4(bit result, bit constraint) { 934 | hdr.leo.layer_2_result = result; 935 | hdr.leo.alu_1_input = hdr.leo.feature_4 + constraint; 936 | } 937 | 938 | action set_3_1_feature5(bit result, bit constraint) { 939 | hdr.leo.layer_2_result = result; 940 | hdr.leo.alu_1_input = hdr.leo.feature_5 + constraint; 941 | } 942 | 943 | table layer_3_1 { 944 | key = { 945 | hdr.leo.layer_1_result : ternary; 946 | hdr.leo.alu_1_input_B : ternary; 947 | hdr.leo.alu_2_input_B : ternary; 948 | hdr.leo.alu_3_input_B : ternary; 949 | } 950 | actions = { 951 | set_leaf; 952 | set_3_1_feature1; 953 | set_3_1_feature2; 954 | set_3_1_feature3; 955 | set_3_1_feature4; 956 | set_3_1_feature5; 957 | NoAction; 958 | } 959 | size = 16; 960 | default_action = NoAction(); 961 | } 962 | 963 | action set_3_2_feature1(bit constraint) { 964 | hdr.leo.alu_2_input = hdr.leo.feature_1 + constraint; 965 | } 966 | 967 | action set_3_2_feature2(bit constraint) { 968 | hdr.leo.alu_2_input = hdr.leo.feature_2 + constraint; 969 | } 970 | 971 | action set_3_2_feature3(bit constraint) { 972 | hdr.leo.alu_2_input = hdr.leo.feature_3 + constraint; 973 | } 974 | 975 | action set_3_2_feature4(bit constraint) { 976 | hdr.leo.alu_2_input = hdr.leo.feature_4 + constraint; 977 | } 978 | 979 | action set_3_2_feature5(bit constraint) { 980 | hdr.leo.alu_2_input = hdr.leo.feature_5 + constraint; 981 | } 982 | 983 | table layer_3_2 { 984 | key = { 985 | hdr.leo.layer_1_result : ternary; 986 | hdr.leo.alu_1_input_B : ternary; 987 | hdr.leo.alu_2_input_B : ternary; 988 | hdr.leo.alu_3_input_B : ternary; 989 | } 990 | actions = { 991 | set_3_2_feature1; 992 | set_3_2_feature2; 993 | set_3_2_feature3; 994 | set_3_2_feature4; 995 | set_3_2_feature5; 996 | NoAction; 997 | } 998 | size = 16; 999 | default_action = NoAction(); 1000 | } 1001 | 1002 | action set_3_3_feature1(bit constraint) { 1003 | hdr.leo.alu_3_input = hdr.leo.feature_1 + constraint; 1004 | } 1005 | 1006 | action set_3_3_feature2(bit constraint) { 1007 | hdr.leo.alu_3_input = hdr.leo.feature_2 + constraint; 1008 | } 1009 | 1010 | action set_3_3_feature3(bit constraint) { 1011 | hdr.leo.alu_3_input = hdr.leo.feature_3 + constraint; 1012 | } 1013 | 1014 | action set_3_3_feature4(bit constraint) { 1015 | hdr.leo.alu_3_input = hdr.leo.feature_4 + constraint; 1016 | } 1017 | 1018 | action set_3_3_feature5(bit constraint) { 1019 | hdr.leo.alu_3_input = hdr.leo.feature_5 + constraint; 1020 | } 1021 | 1022 | table layer_3_3 { 1023 | key = { 1024 | hdr.leo.layer_1_result : ternary; 1025 | hdr.leo.alu_1_input_B : ternary; 1026 | hdr.leo.alu_2_input_B : ternary; 1027 | hdr.leo.alu_3_input_B : ternary; 1028 | } 1029 | actions = { 1030 | set_3_3_feature1; 1031 | set_3_3_feature2; 1032 | set_3_3_feature3; 1033 | set_3_3_feature4; 1034 | set_3_3_feature5; 1035 | NoAction; 1036 | } 1037 | size = 16; 1038 | default_action = NoAction(); 1039 | } 1040 | 1041 | action set_4_1_feature1(bit result, bit constraint) { 1042 | hdr.leo.layer_3_result = result; 1043 | hdr.leo.alu_1_input_B = hdr.leo.feature_1 + constraint; 1044 | } 1045 | 1046 | action set_4_1_feature2(bit result, bit constraint) { 1047 | hdr.leo.layer_3_result = result; 1048 | hdr.leo.alu_1_input_B = hdr.leo.feature_2 + constraint; 1049 | } 1050 | 1051 | action set_4_1_feature3(bit result, bit constraint) { 1052 | hdr.leo.layer_3_result = result; 1053 | hdr.leo.alu_1_input_B = hdr.leo.feature_3 + constraint; 1054 | } 1055 | 1056 | action set_4_1_feature4(bit result, bit constraint) { 1057 | hdr.leo.layer_3_result = result; 1058 | hdr.leo.alu_1_input_B = hdr.leo.feature_4 + constraint; 1059 | } 1060 | 1061 | action set_4_1_feature5(bit result, bit constraint) { 1062 | hdr.leo.layer_3_result = result; 1063 | hdr.leo.alu_1_input_B = hdr.leo.feature_5 + constraint; 1064 | } 1065 | 1066 | table layer_4_1 { 1067 | key = { 1068 | hdr.leo.layer_2_result : ternary; 1069 | hdr.leo.alu_1_input : ternary; 1070 | hdr.leo.alu_2_input : ternary; 1071 | hdr.leo.alu_3_input : ternary; 1072 | } 1073 | actions = { 1074 | set_leaf; 1075 | set_4_1_feature1; 1076 | set_4_1_feature2; 1077 | set_4_1_feature3; 1078 | set_4_1_feature4; 1079 | set_4_1_feature5; 1080 | NoAction; 1081 | } 1082 | size = 64; 1083 | default_action = NoAction(); 1084 | } 1085 | 1086 | action set_4_2_feature1(bit constraint) { 1087 | hdr.leo.alu_2_input_B = hdr.leo.feature_1 + constraint; 1088 | } 1089 | 1090 | action set_4_2_feature2(bit constraint) { 1091 | hdr.leo.alu_2_input_B = hdr.leo.feature_2 + constraint; 1092 | } 1093 | 1094 | action set_4_2_feature3(bit constraint) { 1095 | hdr.leo.alu_2_input_B = hdr.leo.feature_3 + constraint; 1096 | } 1097 | 1098 | action set_4_2_feature4(bit constraint) { 1099 | hdr.leo.alu_2_input_B = hdr.leo.feature_4 + constraint; 1100 | } 1101 | 1102 | action set_4_2_feature5(bit constraint) { 1103 | hdr.leo.alu_2_input_B = hdr.leo.feature_5 + constraint; 1104 | } 1105 | 1106 | table layer_4_2 { 1107 | key = { 1108 | hdr.leo.layer_2_result : ternary; 1109 | hdr.leo.alu_1_input : ternary; 1110 | hdr.leo.alu_2_input : ternary; 1111 | hdr.leo.alu_3_input : ternary; 1112 | } 1113 | actions = { 1114 | set_4_2_feature1; 1115 | set_4_2_feature2; 1116 | set_4_2_feature3; 1117 | set_4_2_feature4; 1118 | set_4_2_feature5; 1119 | NoAction; 1120 | } 1121 | size = 64; 1122 | default_action = NoAction(); 1123 | } 1124 | 1125 | action set_4_3_feature1(bit constraint) { 1126 | hdr.leo.alu_3_input_B = hdr.leo.feature_1 + constraint; 1127 | } 1128 | 1129 | action set_4_3_feature2(bit constraint) { 1130 | hdr.leo.alu_3_input_B = hdr.leo.feature_2 + constraint; 1131 | } 1132 | 1133 | action set_4_3_feature3(bit constraint) { 1134 | hdr.leo.alu_3_input_B = hdr.leo.feature_3 + constraint; 1135 | } 1136 | 1137 | action set_4_3_feature4(bit constraint) { 1138 | hdr.leo.alu_3_input_B = hdr.leo.feature_4 + constraint; 1139 | } 1140 | 1141 | action set_4_3_feature5(bit constraint) { 1142 | hdr.leo.alu_3_input_B = hdr.leo.feature_5 + constraint; 1143 | } 1144 | 1145 | table layer_4_3 { 1146 | key = { 1147 | hdr.leo.layer_2_result : ternary; 1148 | hdr.leo.alu_1_input : ternary; 1149 | hdr.leo.alu_2_input : ternary; 1150 | hdr.leo.alu_3_input : ternary; 1151 | } 1152 | actions = { 1153 | set_4_3_feature1; 1154 | set_4_3_feature2; 1155 | set_4_3_feature3; 1156 | set_4_3_feature4; 1157 | set_4_3_feature5; 1158 | NoAction; 1159 | } 1160 | size = 64; 1161 | default_action = NoAction(); 1162 | } 1163 | 1164 | action set_5_1_feature1(bit result, bit constraint) { 1165 | hdr.leo.layer_4_result = result; 1166 | hdr.leo.alu_1_input = hdr.leo.feature_1 + constraint; 1167 | } 1168 | 1169 | action set_5_1_feature2(bit result, bit constraint) { 1170 | hdr.leo.layer_4_result = result; 1171 | hdr.leo.alu_1_input = hdr.leo.feature_2 + constraint; 1172 | } 1173 | 1174 | action set_5_1_feature3(bit result, bit constraint) { 1175 | hdr.leo.layer_4_result = result; 1176 | hdr.leo.alu_1_input = hdr.leo.feature_3 + constraint; 1177 | } 1178 | 1179 | action set_5_1_feature4(bit result, bit constraint) { 1180 | hdr.leo.layer_4_result = result; 1181 | hdr.leo.alu_1_input = hdr.leo.feature_4 + constraint; 1182 | } 1183 | 1184 | action set_5_1_feature5(bit result, bit constraint) { 1185 | hdr.leo.layer_4_result = result; 1186 | hdr.leo.alu_1_input = hdr.leo.feature_5 + constraint; 1187 | } 1188 | 1189 | table layer_5_1 { 1190 | key = { 1191 | hdr.leo.layer_3_result : ternary; 1192 | hdr.leo.alu_1_input_B : ternary; 1193 | hdr.leo.alu_2_input_B : ternary; 1194 | hdr.leo.alu_3_input_B : ternary; 1195 | } 1196 | actions = { 1197 | set_leaf; 1198 | set_5_1_feature1; 1199 | set_5_1_feature2; 1200 | set_5_1_feature3; 1201 | set_5_1_feature4; 1202 | set_5_1_feature5; 1203 | NoAction; 1204 | } 1205 | size = 256; 1206 | default_action = NoAction(); 1207 | } 1208 | 1209 | action set_5_2_feature1(bit constraint) { 1210 | hdr.leo.alu_2_input = hdr.leo.feature_1 + constraint; 1211 | } 1212 | 1213 | action set_5_2_feature2(bit constraint) { 1214 | hdr.leo.alu_2_input = hdr.leo.feature_2 + constraint; 1215 | } 1216 | 1217 | action set_5_2_feature3(bit constraint) { 1218 | hdr.leo.alu_2_input = hdr.leo.feature_3 + constraint; 1219 | } 1220 | 1221 | action set_5_2_feature4(bit constraint) { 1222 | hdr.leo.alu_2_input = hdr.leo.feature_4 + constraint; 1223 | } 1224 | 1225 | action set_5_2_feature5(bit constraint) { 1226 | hdr.leo.alu_2_input = hdr.leo.feature_5 + constraint; 1227 | } 1228 | 1229 | table layer_5_2 { 1230 | key = { 1231 | hdr.leo.layer_3_result : ternary; 1232 | hdr.leo.alu_1_input_B : ternary; 1233 | hdr.leo.alu_2_input_B : ternary; 1234 | hdr.leo.alu_3_input_B : ternary; 1235 | } 1236 | actions = { 1237 | set_5_2_feature1; 1238 | set_5_2_feature2; 1239 | set_5_2_feature3; 1240 | set_5_2_feature4; 1241 | set_5_2_feature5; 1242 | NoAction; 1243 | } 1244 | size = 256; 1245 | default_action = NoAction(); 1246 | } 1247 | 1248 | action set_5_3_feature1(bit constraint) { 1249 | hdr.leo.alu_3_input = hdr.leo.feature_1 + constraint; 1250 | } 1251 | 1252 | action set_5_3_feature2(bit constraint) { 1253 | hdr.leo.alu_3_input = hdr.leo.feature_2 + constraint; 1254 | } 1255 | 1256 | action set_5_3_feature3(bit constraint) { 1257 | hdr.leo.alu_3_input = hdr.leo.feature_3 + constraint; 1258 | } 1259 | 1260 | action set_5_3_feature4(bit constraint) { 1261 | hdr.leo.alu_3_input = hdr.leo.feature_4 + constraint; 1262 | } 1263 | 1264 | action set_5_3_feature5(bit constraint) { 1265 | hdr.leo.alu_3_input = hdr.leo.feature_5 + constraint; 1266 | } 1267 | 1268 | table layer_5_3 { 1269 | key = { 1270 | hdr.leo.layer_3_result : ternary; 1271 | hdr.leo.alu_1_input_B : ternary; 1272 | hdr.leo.alu_2_input_B : ternary; 1273 | hdr.leo.alu_3_input_B : ternary; 1274 | } 1275 | actions = { 1276 | set_5_3_feature1; 1277 | set_5_3_feature2; 1278 | set_5_3_feature3; 1279 | set_5_3_feature4; 1280 | set_5_3_feature5; 1281 | NoAction; 1282 | } 1283 | size = 256; 1284 | default_action = NoAction(); 1285 | } 1286 | 1287 | table layer_6_1 { 1288 | key = { 1289 | hdr.leo.layer_4_result : ternary; 1290 | hdr.leo.alu_1_input : ternary; 1291 | hdr.leo.alu_2_input : ternary; 1292 | hdr.leo.alu_3_input : ternary; 1293 | } 1294 | actions = { 1295 | set_leaf; 1296 | NoAction; 1297 | } 1298 | size = 1024; 1299 | default_action = NoAction(); 1300 | } 1301 | 1302 | apply { 1303 | layer_1_1.apply(); 1304 | layer_1_2.apply(); 1305 | layer_1_3.apply(); 1306 | layer_2_1.apply(); 1307 | layer_2_2.apply(); 1308 | layer_2_3.apply(); 1309 | layer_3_1.apply(); 1310 | layer_3_2.apply(); 1311 | layer_3_3.apply(); 1312 | layer_4_1.apply(); 1313 | layer_4_2.apply(); 1314 | layer_4_3.apply(); 1315 | layer_5_1.apply(); 1316 | layer_5_2.apply(); 1317 | layer_5_3.apply(); 1318 | layer_6_1.apply(); 1319 | } 1320 | } 1321 | 1322 | // --------------------------------------------------------------------------- 1323 | // Egress Deparser 1324 | // --------------------------------------------------------------------------- 1325 | control SwitchEgressDeparser(packet_out pkt, 1326 | inout header_t hdr, 1327 | in metadata_t eg_md, 1328 | in egress_intrinsic_metadata_for_deparser_t 1329 | eg_intr_dprsr_md 1330 | ) { 1331 | 1332 | apply { 1333 | pkt.emit(hdr.ethernet); 1334 | pkt.emit(hdr.ipv4); 1335 | pkt.emit(hdr.tcp); 1336 | pkt.emit(hdr.leo); 1337 | } 1338 | } 1339 | 1340 | Pipeline(SwitchIngressParser(), 1341 | SwitchIngress(), 1342 | SwitchIngressDeparser(), 1343 | SwitchEgressParser(), 1344 | SwitchEgress(), 1345 | SwitchEgressDeparser()) pipe; 1346 | 1347 | Switch(pipe) main; 1348 | -------------------------------------------------------------------------------- /leo/leo.p4: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #if __TARGET_TOFINO__ == 3 4 | #include 5 | #elif __TARGET_TOFINO__ == 2 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | typedef bit<48> mac_addr_t; 12 | typedef bit<32> ipv4_addr_t; 13 | 14 | typedef bit<16> ether_type_t; 15 | const ether_type_t ETHERTYPE_IPV4 = 16w0x0800; 16 | 17 | typedef bit<8> ip_protocol_t; 18 | const ip_protocol_t IP_PROTOCOLS_TCP = 6; 19 | 20 | // 14 byte 21 | header ethernet_h { 22 | mac_addr_t dst_addr; 23 | mac_addr_t src_addr; 24 | ether_type_t ether_type; 25 | } 26 | 27 | // 20 byte 28 | header ipv4_h { 29 | bit<4> version; 30 | bit<4> ihl; 31 | bit<8> diffserv; 32 | bit<16> total_len; 33 | bit<16> identification; 34 | bit<3> flags; 35 | bit<13> frag_offset; 36 | bit<8> ttl; 37 | ip_protocol_t protocol; 38 | bit<16> hdr_checksum; 39 | ipv4_addr_t src_addr; 40 | ipv4_addr_t dst_addr; 41 | } 42 | 43 | // 20 byte 44 | header tcp_h { 45 | bit<16> src_port; 46 | bit<16> dst_port; 47 | bit<32> seq_no; 48 | bit<32> ack_no; 49 | bit<4> data_offset; 50 | bit<4> res; 51 | bit<1> cwr; 52 | bit<1> ece; 53 | bit<1> urg; 54 | bit<1> ack; 55 | bit<1> psh; 56 | bit<1> rst; 57 | bit<1> syn; 58 | bit<1> fin; 59 | bit<16> window; 60 | bit<16> checksum; 61 | bit<16> urgent_ptr; 62 | } 63 | 64 | #define FEATURE_WIDTH 16 65 | #define LEAF_ID_WIDTH 16 66 | #define ALU_RESULT_WIDTH 8 67 | 68 | header classification_t { 69 | bit leaf; 70 | bit layer_1_result; 71 | bit layer_2_result; 72 | bit layer_3_result; 73 | bit layer_4_result; 74 | bit alu_1_input; 75 | bit alu_1_result; 76 | bit alu_2_input; 77 | bit alu_2_result; 78 | bit alu_3_input; 79 | bit alu_3_result; 80 | bit alu_4_input; 81 | bit alu_4_result; 82 | bit alu_5_input; 83 | bit alu_5_result; 84 | bit alu_6_input; 85 | bit alu_6_result; 86 | bit alu_7_input; 87 | bit alu_7_result; 88 | bit feature_1; 89 | bit feature_2; 90 | 91 | bit<48> start_time; 92 | bit<48> end_time; 93 | bit<48> backup_time; 94 | bit<8> ctrl; 95 | bit<8> dummy; 96 | } 97 | 98 | 99 | header resubmit_header_t { 100 | bit<8> type; 101 | bit<8> class_id; 102 | } 103 | 104 | struct header_t { 105 | ethernet_h ethernet; 106 | ipv4_h ipv4; 107 | tcp_h tcp; 108 | classification_t class; 109 | } 110 | 111 | #include "tofino-util.p4" 112 | 113 | const bit<8> RESUB_TYPE = 255; 114 | 115 | struct metadata_t { 116 | bit<8> resub_type; 117 | resubmit_header_t resub_hdr; 118 | } 119 | 120 | typedef bit<9> egressSpec_t; 121 | 122 | // --------------------------------------------------------------------------- 123 | // Ingress parser 124 | // --------------------------------------------------------------------------- 125 | parser SwitchIngressParser( 126 | packet_in pkt, 127 | out header_t hdr, 128 | out metadata_t ig_md, 129 | out ingress_intrinsic_metadata_t ig_intr_md) { 130 | 131 | state start { 132 | pkt.extract(ig_intr_md); 133 | ig_md.resub_type = 0; 134 | transition select(ig_intr_md.resubmit_flag) { 135 | 1 : parse_resubmit; 136 | 0 : parse_port_metadata; 137 | } 138 | } 139 | 140 | state parse_resubmit { 141 | ig_md.resub_type = pkt.lookahead>()[7:0]; 142 | transition select(ig_md.resub_type) { 143 | RESUB_TYPE : parse_resub; 144 | default : reject; 145 | } 146 | } 147 | 148 | state parse_resub { 149 | pkt.extract(ig_md.resub_hdr); 150 | transition parse_resub_end; 151 | } 152 | 153 | state parse_resub_end { 154 | transition parse_ethernet; 155 | } 156 | 157 | state parse_port_metadata { 158 | pkt.advance(PORT_METADATA_SIZE); 159 | transition parse_ethernet; 160 | } 161 | 162 | state parse_ethernet { 163 | pkt.extract(hdr.ethernet); 164 | transition select(hdr.ethernet.ether_type) { 165 | ETHERTYPE_IPV4: parse_ipv4; 166 | default: reject; 167 | } 168 | } 169 | 170 | state parse_ipv4 { 171 | pkt.extract(hdr.ipv4); 172 | transition select(hdr.ipv4.protocol){ 173 | IP_PROTOCOLS_TCP: parse_tcp; 174 | default: reject; 175 | } 176 | } 177 | 178 | state parse_tcp { 179 | pkt.extract(hdr.tcp); 180 | transition parse_class_hdr; 181 | } 182 | 183 | state parse_class_hdr { 184 | pkt.extract(hdr.class); 185 | transition accept; 186 | } 187 | } 188 | 189 | // --------------------------------------------------------------------------- 190 | // Ingress Deparser 191 | // --------------------------------------------------------------------------- 192 | 193 | control SwitchIngressDeparser( 194 | packet_out pkt, 195 | inout header_t hdr, 196 | in metadata_t ig_md, 197 | in ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md) { 198 | 199 | Checksum() ipv4_checksum; 200 | 201 | apply { 202 | hdr.ipv4.hdr_checksum = ipv4_checksum.update({ 203 | hdr.ipv4.version, 204 | hdr.ipv4.ihl, 205 | hdr.ipv4.diffserv, 206 | hdr.ipv4.total_len, 207 | hdr.ipv4.identification, 208 | hdr.ipv4.flags, 209 | hdr.ipv4.frag_offset, 210 | hdr.ipv4.ttl, 211 | hdr.ipv4.protocol, 212 | hdr.ipv4.src_addr, 213 | hdr.ipv4.dst_addr}); 214 | 215 | pkt.emit(hdr.ethernet); 216 | pkt.emit(hdr.ipv4); 217 | pkt.emit(hdr.tcp); 218 | pkt.emit(hdr.class); 219 | } 220 | } 221 | 222 | // --------------------------------------------------------------------------- 223 | // Ingress 224 | // --------------------------------------------------------------------------- 225 | control SwitchIngress( 226 | inout header_t hdr, 227 | inout metadata_t ig_md, 228 | in ingress_intrinsic_metadata_t ig_intr_md, 229 | in ingress_intrinsic_metadata_from_parser_t ig_prsr_md, 230 | inout ingress_intrinsic_metadata_for_deparser_t ig_dprsr_md, 231 | inout ingress_intrinsic_metadata_for_tm_t ig_tm_md) { 232 | 233 | const PortId_t CPU_PORT = 64; 234 | 235 | action drop() { 236 | ig_dprsr_md.drop_ctl = 1; 237 | } 238 | 239 | action ipv4_forward(egressSpec_t port) { 240 | ig_tm_md.ucast_egress_port = port; 241 | hdr.ipv4.ttl = hdr.ipv4.ttl - 1; 242 | } 243 | 244 | action send_to_cpu() { 245 | ig_tm_md.ucast_egress_port = CPU_PORT; 246 | } 247 | 248 | table ipv4_exact { 249 | key = { 250 | hdr.ipv4.dst_addr: exact; 251 | } 252 | actions = { 253 | ipv4_forward; 254 | send_to_cpu; 255 | drop; 256 | } 257 | size = 10000; 258 | default_action = send_to_cpu(); 259 | } 260 | 261 | action set_leaf(bit leaf) { 262 | hdr.class.leaf = leaf; 263 | } 264 | 265 | action ALU_1_and() { 266 | hdr.class.alu_1_result = hdr.class.alu_1_input & 32768; 267 | } 268 | 269 | action ALU_2_and() { 270 | hdr.class.alu_2_result = hdr.class.alu_2_input & 32768; 271 | } 272 | 273 | action ALU_3_and() { 274 | hdr.class.alu_3_result = hdr.class.alu_3_input & 32768; 275 | } 276 | 277 | action ALU_4_and() { 278 | hdr.class.alu_4_result = hdr.class.alu_4_input & 32768; 279 | } 280 | 281 | action ALU_5_and() { 282 | hdr.class.alu_5_result = hdr.class.alu_5_input & 32768; 283 | } 284 | 285 | action ALU_6_and() { 286 | hdr.class.alu_6_result = hdr.class.alu_6_input & 32768; 287 | } 288 | 289 | action ALU_7_and() { 290 | hdr.class.alu_7_result = hdr.class.alu_7_input & 32768; 291 | } 292 | 293 | action set_1_1_feature1(bit constraint) { 294 | hdr.class.alu_1_input = hdr.class.feature_1 + constraint; 295 | } 296 | 297 | action set_1_1_feature2(bit constraint) { 298 | hdr.class.alu_1_input = hdr.class.feature_2 + constraint; 299 | } 300 | 301 | table layer_1_1 { 302 | key = { 303 | hdr.class.dummy : exact; 304 | } 305 | actions = { 306 | set_1_1_feature1; 307 | set_1_1_feature2; 308 | NoAction; 309 | } 310 | size = 2; 311 | default_action = NoAction(); 312 | } 313 | 314 | action set_1_2_feature1(bit constraint) { 315 | hdr.class.alu_2_input = hdr.class.feature_1 + constraint; 316 | } 317 | 318 | action set_1_2_feature2(bit constraint) { 319 | hdr.class.alu_2_input = hdr.class.feature_2 + constraint; 320 | } 321 | 322 | table layer_1_2 { 323 | key = { 324 | hdr.class.dummy : exact; 325 | } 326 | actions = { 327 | set_1_2_feature1; 328 | set_1_2_feature2; 329 | NoAction; 330 | } 331 | size = 2; 332 | default_action = NoAction(); 333 | } 334 | 335 | action set_1_3_feature1(bit constraint) { 336 | hdr.class.alu_3_input = hdr.class.feature_1 + constraint; 337 | } 338 | 339 | action set_1_3_feature2(bit constraint) { 340 | hdr.class.alu_3_input = hdr.class.feature_2 + constraint; 341 | } 342 | 343 | table layer_1_3 { 344 | key = { 345 | hdr.class.dummy : exact; 346 | } 347 | actions = { 348 | set_1_3_feature1; 349 | set_1_3_feature2; 350 | NoAction; 351 | } 352 | size = 2; 353 | default_action = NoAction(); 354 | } 355 | 356 | action set_1_4_feature1(bit constraint) { 357 | hdr.class.alu_4_input = hdr.class.feature_1 + constraint; 358 | } 359 | 360 | action set_1_4_feature2(bit constraint) { 361 | hdr.class.alu_4_input = hdr.class.feature_2 + constraint; 362 | } 363 | 364 | table layer_1_4 { 365 | key = { 366 | hdr.class.dummy : exact; 367 | } 368 | actions = { 369 | set_1_4_feature1; 370 | set_1_4_feature2; 371 | NoAction; 372 | } 373 | size = 2; 374 | default_action = NoAction(); 375 | } 376 | 377 | action set_1_5_feature1(bit constraint) { 378 | hdr.class.alu_5_input = hdr.class.feature_1 + constraint; 379 | } 380 | 381 | action set_1_5_feature2(bit constraint) { 382 | hdr.class.alu_5_input = hdr.class.feature_2 + constraint; 383 | } 384 | 385 | table layer_1_5 { 386 | key = { 387 | hdr.class.dummy : exact; 388 | } 389 | actions = { 390 | set_1_5_feature1; 391 | set_1_5_feature2; 392 | NoAction; 393 | } 394 | size = 2; 395 | default_action = NoAction(); 396 | } 397 | 398 | action set_1_6_feature1(bit constraint) { 399 | hdr.class.alu_6_input = hdr.class.feature_1 + constraint; 400 | } 401 | 402 | action set_1_6_feature2(bit constraint) { 403 | hdr.class.alu_6_input = hdr.class.feature_2 + constraint; 404 | } 405 | 406 | table layer_1_6 { 407 | key = { 408 | hdr.class.dummy : exact; 409 | } 410 | actions = { 411 | set_1_6_feature1; 412 | set_1_6_feature2; 413 | NoAction; 414 | } 415 | size = 2; 416 | default_action = NoAction(); 417 | } 418 | 419 | action set_1_7_feature1(bit constraint) { 420 | hdr.class.alu_7_input = hdr.class.feature_1 + constraint; 421 | } 422 | 423 | action set_1_7_feature2(bit constraint) { 424 | hdr.class.alu_7_input = hdr.class.feature_2 + constraint; 425 | } 426 | 427 | table layer_1_7 { 428 | key = { 429 | hdr.class.dummy : exact; 430 | } 431 | actions = { 432 | set_1_7_feature1; 433 | set_1_7_feature2; 434 | NoAction; 435 | } 436 | size = 2; 437 | default_action = NoAction(); 438 | } 439 | 440 | action set_2_1_feature1(bit result, bit constraint) { 441 | hdr.class.layer_1_result = result; 442 | hdr.class.alu_1_input = hdr.class.feature_1 + constraint; 443 | } 444 | 445 | action set_2_1_feature2(bit result, bit constraint) { 446 | hdr.class.layer_1_result = result; 447 | hdr.class.alu_1_input = hdr.class.feature_2 + constraint; 448 | } 449 | 450 | table layer_2_1 { 451 | key = { 452 | hdr.class.alu_1_result : exact; 453 | hdr.class.alu_2_result : exact; 454 | hdr.class.alu_3_result : exact; 455 | hdr.class.alu_4_result : exact; 456 | hdr.class.alu_5_result : exact; 457 | hdr.class.alu_6_result : exact; 458 | hdr.class.alu_7_result : exact; 459 | } 460 | actions = { 461 | set_leaf; 462 | set_2_1_feature1; 463 | set_2_1_feature2; 464 | NoAction; 465 | } 466 | size = 256; 467 | default_action = NoAction(); 468 | } 469 | 470 | action set_2_2_feature1(bit constraint) { 471 | hdr.class.alu_2_input = hdr.class.feature_1 + constraint; 472 | } 473 | 474 | action set_2_2_feature2(bit constraint) { 475 | hdr.class.alu_2_input = hdr.class.feature_2 + constraint; 476 | } 477 | 478 | table layer_2_2 { 479 | key = { 480 | hdr.class.alu_1_result : exact; 481 | hdr.class.alu_2_result : exact; 482 | hdr.class.alu_3_result : exact; 483 | hdr.class.alu_4_result : exact; 484 | hdr.class.alu_5_result : exact; 485 | hdr.class.alu_6_result : exact; 486 | hdr.class.alu_7_result : exact; 487 | } 488 | actions = { 489 | set_2_2_feature1; 490 | set_2_2_feature2; 491 | NoAction; 492 | } 493 | size = 256; 494 | default_action = NoAction(); 495 | } 496 | 497 | action set_2_3_feature1(bit constraint) { 498 | hdr.class.alu_3_input = hdr.class.feature_1 + constraint; 499 | } 500 | 501 | action set_2_3_feature2(bit constraint) { 502 | hdr.class.alu_3_input = hdr.class.feature_2 + constraint; 503 | } 504 | 505 | table layer_2_3 { 506 | key = { 507 | hdr.class.alu_1_result : exact; 508 | hdr.class.alu_2_result : exact; 509 | hdr.class.alu_3_result : exact; 510 | hdr.class.alu_4_result : exact; 511 | hdr.class.alu_5_result : exact; 512 | hdr.class.alu_6_result : exact; 513 | hdr.class.alu_7_result : exact; 514 | } 515 | actions = { 516 | set_2_3_feature1; 517 | set_2_3_feature2; 518 | NoAction; 519 | } 520 | size = 256; 521 | default_action = NoAction(); 522 | } 523 | 524 | action set_2_4_feature1(bit constraint) { 525 | hdr.class.alu_4_input = hdr.class.feature_1 + constraint; 526 | } 527 | 528 | action set_2_4_feature2(bit constraint) { 529 | hdr.class.alu_4_input = hdr.class.feature_2 + constraint; 530 | } 531 | 532 | table layer_2_4 { 533 | key = { 534 | hdr.class.alu_1_result : exact; 535 | hdr.class.alu_2_result : exact; 536 | hdr.class.alu_3_result : exact; 537 | hdr.class.alu_4_result : exact; 538 | hdr.class.alu_5_result : exact; 539 | hdr.class.alu_6_result : exact; 540 | hdr.class.alu_7_result : exact; 541 | } 542 | actions = { 543 | set_2_4_feature1; 544 | set_2_4_feature2; 545 | NoAction; 546 | } 547 | size = 256; 548 | default_action = NoAction(); 549 | } 550 | 551 | action set_2_5_feature1(bit constraint) { 552 | hdr.class.alu_5_input = hdr.class.feature_1 + constraint; 553 | } 554 | 555 | action set_2_5_feature2(bit constraint) { 556 | hdr.class.alu_5_input = hdr.class.feature_2 + constraint; 557 | } 558 | 559 | table layer_2_5 { 560 | key = { 561 | hdr.class.alu_1_result : exact; 562 | hdr.class.alu_2_result : exact; 563 | hdr.class.alu_3_result : exact; 564 | hdr.class.alu_4_result : exact; 565 | hdr.class.alu_5_result : exact; 566 | hdr.class.alu_6_result : exact; 567 | hdr.class.alu_7_result : exact; 568 | } 569 | actions = { 570 | set_2_5_feature1; 571 | set_2_5_feature2; 572 | NoAction; 573 | } 574 | size = 256; 575 | default_action = NoAction(); 576 | } 577 | 578 | action set_2_6_feature1(bit constraint) { 579 | hdr.class.alu_6_input = hdr.class.feature_1 + constraint; 580 | } 581 | 582 | action set_2_6_feature2(bit constraint) { 583 | hdr.class.alu_6_input = hdr.class.feature_2 + constraint; 584 | } 585 | 586 | table layer_2_6 { 587 | key = { 588 | hdr.class.alu_1_result : exact; 589 | hdr.class.alu_2_result : exact; 590 | hdr.class.alu_3_result : exact; 591 | hdr.class.alu_4_result : exact; 592 | hdr.class.alu_5_result : exact; 593 | hdr.class.alu_6_result : exact; 594 | hdr.class.alu_7_result : exact; 595 | } 596 | actions = { 597 | set_2_6_feature1; 598 | set_2_6_feature2; 599 | NoAction; 600 | } 601 | size = 256; 602 | default_action = NoAction(); 603 | } 604 | 605 | action set_2_7_feature1(bit constraint) { 606 | hdr.class.alu_7_input = hdr.class.feature_1 + constraint; 607 | } 608 | 609 | action set_2_7_feature2(bit constraint) { 610 | hdr.class.alu_7_input = hdr.class.feature_2 + constraint; 611 | } 612 | 613 | table layer_2_7 { 614 | key = { 615 | hdr.class.alu_1_result : exact; 616 | hdr.class.alu_2_result : exact; 617 | hdr.class.alu_3_result : exact; 618 | hdr.class.alu_4_result : exact; 619 | hdr.class.alu_5_result : exact; 620 | hdr.class.alu_6_result : exact; 621 | hdr.class.alu_7_result : exact; 622 | } 623 | actions = { 624 | set_2_7_feature1; 625 | set_2_7_feature2; 626 | NoAction; 627 | } 628 | size = 256; 629 | default_action = NoAction(); 630 | } 631 | 632 | action set_3_1_feature1(bit result, bit constraint) { 633 | hdr.class.layer_2_result = result; 634 | hdr.class.alu_1_input = hdr.class.feature_1 + constraint; 635 | } 636 | 637 | action set_3_1_feature2(bit result, bit constraint) { 638 | hdr.class.layer_2_result = result; 639 | hdr.class.alu_1_input = hdr.class.feature_2 + constraint; 640 | } 641 | 642 | table layer_3_1 { 643 | key = { 644 | hdr.class.layer_1_result : exact; 645 | hdr.class.alu_1_result : exact; 646 | hdr.class.alu_2_result : exact; 647 | hdr.class.alu_3_result : exact; 648 | hdr.class.alu_4_result : exact; 649 | hdr.class.alu_5_result : exact; 650 | hdr.class.alu_6_result : exact; 651 | hdr.class.alu_7_result : exact; 652 | } 653 | actions = { 654 | set_leaf; 655 | set_3_1_feature1; 656 | set_3_1_feature2; 657 | NoAction; 658 | } 659 | size = 2048; 660 | default_action = NoAction(); 661 | } 662 | 663 | action set_3_2_feature1(bit constraint) { 664 | hdr.class.alu_2_input = hdr.class.feature_1 + constraint; 665 | } 666 | 667 | action set_3_2_feature2(bit constraint) { 668 | hdr.class.alu_2_input = hdr.class.feature_2 + constraint; 669 | } 670 | 671 | table layer_3_2 { 672 | key = { 673 | hdr.class.layer_1_result : exact; 674 | hdr.class.alu_1_result : exact; 675 | hdr.class.alu_2_result : exact; 676 | hdr.class.alu_3_result : exact; 677 | hdr.class.alu_4_result : exact; 678 | hdr.class.alu_5_result : exact; 679 | hdr.class.alu_6_result : exact; 680 | hdr.class.alu_7_result : exact; 681 | } 682 | actions = { 683 | set_3_2_feature1; 684 | set_3_2_feature2; 685 | NoAction; 686 | } 687 | size = 2048; 688 | default_action = NoAction(); 689 | } 690 | 691 | action set_3_3_feature1(bit constraint) { 692 | hdr.class.alu_3_input = hdr.class.feature_1 + constraint; 693 | } 694 | 695 | action set_3_3_feature2(bit constraint) { 696 | hdr.class.alu_3_input = hdr.class.feature_2 + constraint; 697 | } 698 | 699 | table layer_3_3 { 700 | key = { 701 | hdr.class.layer_1_result : exact; 702 | hdr.class.alu_1_result : exact; 703 | hdr.class.alu_2_result : exact; 704 | hdr.class.alu_3_result : exact; 705 | hdr.class.alu_4_result : exact; 706 | hdr.class.alu_5_result : exact; 707 | hdr.class.alu_6_result : exact; 708 | hdr.class.alu_7_result : exact; 709 | } 710 | actions = { 711 | set_3_3_feature1; 712 | set_3_3_feature2; 713 | NoAction; 714 | } 715 | size = 2048; 716 | default_action = NoAction(); 717 | } 718 | 719 | action set_3_4_feature1(bit constraint) { 720 | hdr.class.alu_4_input = hdr.class.feature_1 + constraint; 721 | } 722 | 723 | action set_3_4_feature2(bit constraint) { 724 | hdr.class.alu_4_input = hdr.class.feature_2 + constraint; 725 | } 726 | 727 | table layer_3_4 { 728 | key = { 729 | hdr.class.layer_1_result : exact; 730 | hdr.class.alu_1_result : exact; 731 | hdr.class.alu_2_result : exact; 732 | hdr.class.alu_3_result : exact; 733 | hdr.class.alu_4_result : exact; 734 | hdr.class.alu_5_result : exact; 735 | hdr.class.alu_6_result : exact; 736 | hdr.class.alu_7_result : exact; 737 | } 738 | actions = { 739 | set_3_4_feature1; 740 | set_3_4_feature2; 741 | NoAction; 742 | } 743 | size = 2048; 744 | default_action = NoAction(); 745 | } 746 | 747 | action set_3_5_feature1(bit constraint) { 748 | hdr.class.alu_5_input = hdr.class.feature_1 + constraint; 749 | } 750 | 751 | action set_3_5_feature2(bit constraint) { 752 | hdr.class.alu_5_input = hdr.class.feature_2 + constraint; 753 | } 754 | 755 | table layer_3_5 { 756 | key = { 757 | hdr.class.layer_1_result : exact; 758 | hdr.class.alu_1_result : exact; 759 | hdr.class.alu_2_result : exact; 760 | hdr.class.alu_3_result : exact; 761 | hdr.class.alu_4_result : exact; 762 | hdr.class.alu_5_result : exact; 763 | hdr.class.alu_6_result : exact; 764 | hdr.class.alu_7_result : exact; 765 | } 766 | actions = { 767 | set_3_5_feature1; 768 | set_3_5_feature2; 769 | NoAction; 770 | } 771 | size = 2048; 772 | default_action = NoAction(); 773 | } 774 | 775 | action set_3_6_feature1(bit constraint) { 776 | hdr.class.alu_6_input = hdr.class.feature_1 + constraint; 777 | } 778 | 779 | action set_3_6_feature2(bit constraint) { 780 | hdr.class.alu_6_input = hdr.class.feature_2 + constraint; 781 | } 782 | 783 | table layer_3_6 { 784 | key = { 785 | hdr.class.layer_1_result : exact; 786 | hdr.class.alu_1_result : exact; 787 | hdr.class.alu_2_result : exact; 788 | hdr.class.alu_3_result : exact; 789 | hdr.class.alu_4_result : exact; 790 | hdr.class.alu_5_result : exact; 791 | hdr.class.alu_6_result : exact; 792 | hdr.class.alu_7_result : exact; 793 | } 794 | actions = { 795 | set_3_6_feature1; 796 | set_3_6_feature2; 797 | NoAction; 798 | } 799 | size = 2048; 800 | default_action = NoAction(); 801 | } 802 | 803 | action set_3_7_feature1(bit constraint) { 804 | hdr.class.alu_7_input = hdr.class.feature_1 + constraint; 805 | } 806 | 807 | action set_3_7_feature2(bit constraint) { 808 | hdr.class.alu_7_input = hdr.class.feature_2 + constraint; 809 | } 810 | 811 | table layer_3_7 { 812 | key = { 813 | hdr.class.layer_1_result : exact; 814 | hdr.class.alu_1_result : exact; 815 | hdr.class.alu_2_result : exact; 816 | hdr.class.alu_3_result : exact; 817 | hdr.class.alu_4_result : exact; 818 | hdr.class.alu_5_result : exact; 819 | hdr.class.alu_6_result : exact; 820 | hdr.class.alu_7_result : exact; 821 | } 822 | actions = { 823 | set_3_7_feature1; 824 | set_3_7_feature2; 825 | NoAction; 826 | } 827 | size = 2048; 828 | default_action = NoAction(); 829 | } 830 | 831 | action set_4_1_feature1(bit result, bit constraint) { 832 | hdr.class.layer_3_result = result; 833 | hdr.class.alu_1_input = hdr.class.feature_1 + constraint; 834 | } 835 | 836 | action set_4_1_feature2(bit result, bit constraint) { 837 | hdr.class.layer_3_result = result; 838 | hdr.class.alu_1_input = hdr.class.feature_2 + constraint; 839 | } 840 | 841 | table layer_4_1 { 842 | key = { 843 | hdr.class.layer_2_result : exact; 844 | hdr.class.alu_1_result : exact; 845 | hdr.class.alu_2_result : exact; 846 | hdr.class.alu_3_result : exact; 847 | hdr.class.alu_4_result : exact; 848 | hdr.class.alu_5_result : exact; 849 | hdr.class.alu_6_result : exact; 850 | hdr.class.alu_7_result : exact; 851 | } 852 | actions = { 853 | set_leaf; 854 | set_4_1_feature1; 855 | set_4_1_feature2; 856 | NoAction; 857 | } 858 | size = 16384; 859 | default_action = NoAction(); 860 | } 861 | 862 | action set_4_2_feature1(bit constraint) { 863 | hdr.class.alu_2_input = hdr.class.feature_1 + constraint; 864 | } 865 | 866 | action set_4_2_feature2(bit constraint) { 867 | hdr.class.alu_2_input = hdr.class.feature_2 + constraint; 868 | } 869 | 870 | table layer_4_2 { 871 | key = { 872 | hdr.class.layer_2_result : exact; 873 | hdr.class.alu_1_result : exact; 874 | hdr.class.alu_2_result : exact; 875 | hdr.class.alu_3_result : exact; 876 | hdr.class.alu_4_result : exact; 877 | hdr.class.alu_5_result : exact; 878 | hdr.class.alu_6_result : exact; 879 | hdr.class.alu_7_result : exact; 880 | } 881 | actions = { 882 | set_4_2_feature1; 883 | set_4_2_feature2; 884 | NoAction; 885 | } 886 | size = 16384; 887 | default_action = NoAction(); 888 | } 889 | 890 | action set_4_3_feature1(bit constraint) { 891 | hdr.class.alu_3_input = hdr.class.feature_1 + constraint; 892 | } 893 | 894 | action set_4_3_feature2(bit constraint) { 895 | hdr.class.alu_3_input = hdr.class.feature_2 + constraint; 896 | } 897 | 898 | table layer_4_3 { 899 | key = { 900 | hdr.class.layer_2_result : exact; 901 | hdr.class.alu_1_result : exact; 902 | hdr.class.alu_2_result : exact; 903 | hdr.class.alu_3_result : exact; 904 | hdr.class.alu_4_result : exact; 905 | hdr.class.alu_5_result : exact; 906 | hdr.class.alu_6_result : exact; 907 | hdr.class.alu_7_result : exact; 908 | } 909 | actions = { 910 | set_4_3_feature1; 911 | set_4_3_feature2; 912 | NoAction; 913 | } 914 | size = 16384; 915 | default_action = NoAction(); 916 | } 917 | 918 | action set_4_4_feature1(bit constraint) { 919 | hdr.class.alu_4_input = hdr.class.feature_1 + constraint; 920 | } 921 | 922 | action set_4_4_feature2(bit constraint) { 923 | hdr.class.alu_4_input = hdr.class.feature_2 + constraint; 924 | } 925 | 926 | table layer_4_4 { 927 | key = { 928 | hdr.class.layer_2_result : exact; 929 | hdr.class.alu_1_result : exact; 930 | hdr.class.alu_2_result : exact; 931 | hdr.class.alu_3_result : exact; 932 | hdr.class.alu_4_result : exact; 933 | hdr.class.alu_5_result : exact; 934 | hdr.class.alu_6_result : exact; 935 | hdr.class.alu_7_result : exact; 936 | } 937 | actions = { 938 | set_4_4_feature1; 939 | set_4_4_feature2; 940 | NoAction; 941 | } 942 | size = 16384; 943 | default_action = NoAction(); 944 | } 945 | 946 | action set_4_5_feature1(bit constraint) { 947 | hdr.class.alu_5_input = hdr.class.feature_1 + constraint; 948 | } 949 | 950 | action set_4_5_feature2(bit constraint) { 951 | hdr.class.alu_5_input = hdr.class.feature_2 + constraint; 952 | } 953 | 954 | table layer_4_5 { 955 | key = { 956 | hdr.class.layer_2_result : exact; 957 | hdr.class.alu_1_result : exact; 958 | hdr.class.alu_2_result : exact; 959 | hdr.class.alu_3_result : exact; 960 | hdr.class.alu_4_result : exact; 961 | hdr.class.alu_5_result : exact; 962 | hdr.class.alu_6_result : exact; 963 | hdr.class.alu_7_result : exact; 964 | } 965 | actions = { 966 | set_4_5_feature1; 967 | set_4_5_feature2; 968 | NoAction; 969 | } 970 | size = 16384; 971 | default_action = NoAction(); 972 | } 973 | 974 | action set_4_6_feature1(bit constraint) { 975 | hdr.class.alu_6_input = hdr.class.feature_1 + constraint; 976 | } 977 | 978 | action set_4_6_feature2(bit constraint) { 979 | hdr.class.alu_6_input = hdr.class.feature_2 + constraint; 980 | } 981 | 982 | table layer_4_6 { 983 | key = { 984 | hdr.class.layer_2_result : exact; 985 | hdr.class.alu_1_result : exact; 986 | hdr.class.alu_2_result : exact; 987 | hdr.class.alu_3_result : exact; 988 | hdr.class.alu_4_result : exact; 989 | hdr.class.alu_5_result : exact; 990 | hdr.class.alu_6_result : exact; 991 | hdr.class.alu_7_result : exact; 992 | } 993 | actions = { 994 | set_4_6_feature1; 995 | set_4_6_feature2; 996 | NoAction; 997 | } 998 | size = 16384; 999 | default_action = NoAction(); 1000 | } 1001 | 1002 | action set_4_7_feature1(bit constraint) { 1003 | hdr.class.alu_7_input = hdr.class.feature_1 + constraint; 1004 | } 1005 | 1006 | action set_4_7_feature2(bit constraint) { 1007 | hdr.class.alu_7_input = hdr.class.feature_2 + constraint; 1008 | } 1009 | 1010 | table layer_4_7 { 1011 | key = { 1012 | hdr.class.layer_2_result : exact; 1013 | hdr.class.alu_1_result : exact; 1014 | hdr.class.alu_2_result : exact; 1015 | hdr.class.alu_3_result : exact; 1016 | hdr.class.alu_4_result : exact; 1017 | hdr.class.alu_5_result : exact; 1018 | hdr.class.alu_6_result : exact; 1019 | hdr.class.alu_7_result : exact; 1020 | } 1021 | actions = { 1022 | set_4_7_feature1; 1023 | set_4_7_feature2; 1024 | NoAction; 1025 | } 1026 | size = 16384; 1027 | default_action = NoAction(); 1028 | } 1029 | 1030 | action set_5_1_feature1(bit result, bit constraint) { 1031 | hdr.class.layer_4_result = result; 1032 | hdr.class.alu_1_input = hdr.class.feature_1 + constraint; 1033 | } 1034 | 1035 | action set_5_1_feature2(bit result, bit constraint) { 1036 | hdr.class.layer_4_result = result; 1037 | hdr.class.alu_1_input = hdr.class.feature_2 + constraint; 1038 | } 1039 | 1040 | table layer_5_1 { 1041 | key = { 1042 | hdr.class.layer_3_result : exact; 1043 | hdr.class.alu_1_result : exact; 1044 | hdr.class.alu_2_result : exact; 1045 | hdr.class.alu_3_result : exact; 1046 | hdr.class.alu_4_result : exact; 1047 | hdr.class.alu_5_result : exact; 1048 | hdr.class.alu_6_result : exact; 1049 | hdr.class.alu_7_result : exact; 1050 | } 1051 | actions = { 1052 | set_leaf; 1053 | set_5_1_feature1; 1054 | set_5_1_feature2; 1055 | NoAction; 1056 | } 1057 | size = 131072; 1058 | default_action = NoAction(); 1059 | } 1060 | 1061 | action set_5_2_feature1(bit constraint) { 1062 | hdr.class.alu_2_input = hdr.class.feature_1 + constraint; 1063 | } 1064 | 1065 | action set_5_2_feature2(bit constraint) { 1066 | hdr.class.alu_2_input = hdr.class.feature_2 + constraint; 1067 | } 1068 | 1069 | table layer_5_2 { 1070 | key = { 1071 | hdr.class.layer_3_result : exact; 1072 | hdr.class.alu_1_result : exact; 1073 | hdr.class.alu_2_result : exact; 1074 | hdr.class.alu_3_result : exact; 1075 | hdr.class.alu_4_result : exact; 1076 | hdr.class.alu_5_result : exact; 1077 | hdr.class.alu_6_result : exact; 1078 | hdr.class.alu_7_result : exact; 1079 | } 1080 | actions = { 1081 | set_5_2_feature1; 1082 | set_5_2_feature2; 1083 | NoAction; 1084 | } 1085 | size = 131072; 1086 | default_action = NoAction(); 1087 | } 1088 | 1089 | action set_5_3_feature1(bit constraint) { 1090 | hdr.class.alu_3_input = hdr.class.feature_1 + constraint; 1091 | } 1092 | 1093 | action set_5_3_feature2(bit constraint) { 1094 | hdr.class.alu_3_input = hdr.class.feature_2 + constraint; 1095 | } 1096 | 1097 | table layer_5_3 { 1098 | key = { 1099 | hdr.class.layer_3_result : exact; 1100 | hdr.class.alu_1_result : exact; 1101 | hdr.class.alu_2_result : exact; 1102 | hdr.class.alu_3_result : exact; 1103 | hdr.class.alu_4_result : exact; 1104 | hdr.class.alu_5_result : exact; 1105 | hdr.class.alu_6_result : exact; 1106 | hdr.class.alu_7_result : exact; 1107 | } 1108 | actions = { 1109 | set_5_3_feature1; 1110 | set_5_3_feature2; 1111 | NoAction; 1112 | } 1113 | size = 131072; 1114 | default_action = NoAction(); 1115 | } 1116 | 1117 | action set_5_4_feature1(bit constraint) { 1118 | hdr.class.alu_4_input = hdr.class.feature_1 + constraint; 1119 | } 1120 | 1121 | action set_5_4_feature2(bit constraint) { 1122 | hdr.class.alu_4_input = hdr.class.feature_2 + constraint; 1123 | } 1124 | 1125 | table layer_5_4 { 1126 | key = { 1127 | hdr.class.layer_3_result : exact; 1128 | hdr.class.alu_1_result : exact; 1129 | hdr.class.alu_2_result : exact; 1130 | hdr.class.alu_3_result : exact; 1131 | hdr.class.alu_4_result : exact; 1132 | hdr.class.alu_5_result : exact; 1133 | hdr.class.alu_6_result : exact; 1134 | hdr.class.alu_7_result : exact; 1135 | } 1136 | actions = { 1137 | set_5_4_feature1; 1138 | set_5_4_feature2; 1139 | NoAction; 1140 | } 1141 | size = 131072; 1142 | default_action = NoAction(); 1143 | } 1144 | 1145 | action set_5_5_feature1(bit constraint) { 1146 | hdr.class.alu_5_input = hdr.class.feature_1 + constraint; 1147 | } 1148 | 1149 | action set_5_5_feature2(bit constraint) { 1150 | hdr.class.alu_5_input = hdr.class.feature_2 + constraint; 1151 | } 1152 | 1153 | table layer_5_5 { 1154 | key = { 1155 | hdr.class.layer_3_result : exact; 1156 | hdr.class.alu_1_result : exact; 1157 | hdr.class.alu_2_result : exact; 1158 | hdr.class.alu_3_result : exact; 1159 | hdr.class.alu_4_result : exact; 1160 | hdr.class.alu_5_result : exact; 1161 | hdr.class.alu_6_result : exact; 1162 | hdr.class.alu_7_result : exact; 1163 | } 1164 | actions = { 1165 | set_5_5_feature1; 1166 | set_5_5_feature2; 1167 | NoAction; 1168 | } 1169 | size = 131072; 1170 | default_action = NoAction(); 1171 | } 1172 | 1173 | action set_5_6_feature1(bit constraint) { 1174 | hdr.class.alu_6_input = hdr.class.feature_1 + constraint; 1175 | } 1176 | 1177 | action set_5_6_feature2(bit constraint) { 1178 | hdr.class.alu_6_input = hdr.class.feature_2 + constraint; 1179 | } 1180 | 1181 | table layer_5_6 { 1182 | key = { 1183 | hdr.class.layer_3_result : exact; 1184 | hdr.class.alu_1_result : exact; 1185 | hdr.class.alu_2_result : exact; 1186 | hdr.class.alu_3_result : exact; 1187 | hdr.class.alu_4_result : exact; 1188 | hdr.class.alu_5_result : exact; 1189 | hdr.class.alu_6_result : exact; 1190 | hdr.class.alu_7_result : exact; 1191 | } 1192 | actions = { 1193 | set_5_6_feature1; 1194 | set_5_6_feature2; 1195 | NoAction; 1196 | } 1197 | size = 131072; 1198 | default_action = NoAction(); 1199 | } 1200 | 1201 | action set_5_7_feature1(bit constraint) { 1202 | hdr.class.alu_7_input = hdr.class.feature_1 + constraint; 1203 | } 1204 | 1205 | action set_5_7_feature2(bit constraint) { 1206 | hdr.class.alu_7_input = hdr.class.feature_2 + constraint; 1207 | } 1208 | 1209 | table layer_5_7 { 1210 | key = { 1211 | hdr.class.layer_3_result : exact; 1212 | hdr.class.alu_1_result : exact; 1213 | hdr.class.alu_2_result : exact; 1214 | hdr.class.alu_3_result : exact; 1215 | hdr.class.alu_4_result : exact; 1216 | hdr.class.alu_5_result : exact; 1217 | hdr.class.alu_6_result : exact; 1218 | hdr.class.alu_7_result : exact; 1219 | } 1220 | actions = { 1221 | set_5_7_feature1; 1222 | set_5_7_feature2; 1223 | NoAction; 1224 | } 1225 | size = 131072; 1226 | default_action = NoAction(); 1227 | } 1228 | 1229 | table layer_6_1 { 1230 | key = { 1231 | hdr.class.layer_4_result : exact; 1232 | hdr.class.alu_1_result : exact; 1233 | hdr.class.alu_2_result : exact; 1234 | hdr.class.alu_3_result : exact; 1235 | hdr.class.alu_4_result : exact; 1236 | hdr.class.alu_5_result : exact; 1237 | hdr.class.alu_6_result : exact; 1238 | hdr.class.alu_7_result : exact; 1239 | } 1240 | actions = { 1241 | set_leaf; 1242 | NoAction; 1243 | } 1244 | size = 1048576; 1245 | default_action = NoAction(); 1246 | } 1247 | 1248 | apply { 1249 | hdr.class.start_time = ig_intr_md.ingress_mac_tstamp; 1250 | 1251 | layer_1_1.apply(); 1252 | layer_1_2.apply(); 1253 | layer_1_3.apply(); 1254 | layer_1_4.apply(); 1255 | layer_1_5.apply(); 1256 | layer_1_6.apply(); 1257 | layer_1_7.apply(); 1258 | ALU_1_and(); 1259 | ALU_2_and(); 1260 | ALU_3_and(); 1261 | ALU_4_and(); 1262 | ALU_5_and(); 1263 | ALU_6_and(); 1264 | ALU_7_and(); 1265 | layer_2_1.apply(); 1266 | layer_2_2.apply(); 1267 | layer_2_3.apply(); 1268 | layer_2_4.apply(); 1269 | layer_2_5.apply(); 1270 | layer_2_6.apply(); 1271 | layer_2_7.apply(); 1272 | ALU_1_and(); 1273 | ALU_2_and(); 1274 | ALU_3_and(); 1275 | ALU_4_and(); 1276 | ALU_5_and(); 1277 | ALU_6_and(); 1278 | ALU_7_and(); 1279 | layer_3_1.apply(); 1280 | layer_3_2.apply(); 1281 | layer_3_3.apply(); 1282 | layer_3_4.apply(); 1283 | layer_3_5.apply(); 1284 | layer_3_6.apply(); 1285 | layer_3_7.apply(); 1286 | ALU_1_and(); 1287 | ALU_2_and(); 1288 | ALU_3_and(); 1289 | ALU_4_and(); 1290 | ALU_5_and(); 1291 | ALU_6_and(); 1292 | ALU_7_and(); 1293 | layer_4_1.apply(); 1294 | layer_4_2.apply(); 1295 | layer_4_3.apply(); 1296 | layer_4_4.apply(); 1297 | layer_4_5.apply(); 1298 | layer_4_6.apply(); 1299 | layer_4_7.apply(); 1300 | ALU_1_and(); 1301 | ALU_2_and(); 1302 | ALU_3_and(); 1303 | ALU_4_and(); 1304 | ALU_5_and(); 1305 | ALU_6_and(); 1306 | ALU_7_and(); 1307 | layer_5_1.apply(); 1308 | layer_5_2.apply(); 1309 | layer_5_3.apply(); 1310 | layer_5_4.apply(); 1311 | layer_5_5.apply(); 1312 | layer_5_6.apply(); 1313 | layer_5_7.apply(); 1314 | ALU_1_and(); 1315 | ALU_2_and(); 1316 | ALU_3_and(); 1317 | ALU_4_and(); 1318 | ALU_5_and(); 1319 | ALU_6_and(); 1320 | ALU_7_and(); 1321 | layer_6_1.apply(); 1322 | 1323 | 1324 | if (hdr.ipv4.isValid()) { 1325 | ipv4_exact.apply(); 1326 | } 1327 | } 1328 | } 1329 | 1330 | // --------------------------------------------------------------------------- 1331 | // Egress Parser 1332 | // --------------------------------------------------------------------------- 1333 | parser SwitchEgressParser( 1334 | packet_in pkt, 1335 | out header_t hdr, 1336 | out metadata_t eg_md, 1337 | out egress_intrinsic_metadata_t eg_intr_md) { 1338 | 1339 | TofinoEgressParser() tofino_parser; 1340 | 1341 | state start { 1342 | tofino_parser.apply(pkt, eg_intr_md); 1343 | transition parse_ethernet; 1344 | } 1345 | 1346 | state parse_ethernet { 1347 | pkt.extract(hdr.ethernet); 1348 | transition select(hdr.ethernet.ether_type) { 1349 | ETHERTYPE_IPV4 : parse_ipv4; 1350 | default : reject; 1351 | } 1352 | } 1353 | 1354 | state parse_ipv4 { 1355 | pkt.extract(hdr.ipv4); 1356 | transition select(hdr.ipv4.protocol){ 1357 | IP_PROTOCOLS_TCP: parse_tcp; 1358 | default: reject; 1359 | } 1360 | } 1361 | 1362 | state parse_tcp { 1363 | pkt.extract(hdr.tcp); 1364 | transition parse_class_hdr; 1365 | } 1366 | 1367 | state parse_class_hdr { 1368 | pkt.extract(hdr.class); 1369 | transition accept; 1370 | } 1371 | } 1372 | 1373 | 1374 | // --------------------------------------------------------------------------- 1375 | // Egress 1376 | // --------------------------------------------------------------------------- 1377 | control SwitchEgress( 1378 | inout header_t hdr, 1379 | inout metadata_t eg_md, 1380 | in egress_intrinsic_metadata_t eg_intr_md, 1381 | in egress_intrinsic_metadata_from_parser_t eg_intr_from_prsr, 1382 | inout egress_intrinsic_metadata_for_deparser_t eg_intr_md_for_dprsr, 1383 | inout egress_intrinsic_metadata_for_output_port_t eg_intr_md_for_oport) { 1384 | 1385 | apply { 1386 | hdr.class.end_time = eg_intr_from_prsr.global_tstamp; 1387 | hdr.class.ctrl = 0xff; 1388 | } 1389 | } 1390 | 1391 | // --------------------------------------------------------------------------- 1392 | // Egress Deparser 1393 | // --------------------------------------------------------------------------- 1394 | control SwitchEgressDeparser(packet_out pkt, 1395 | inout header_t hdr, 1396 | in metadata_t eg_md, 1397 | in egress_intrinsic_metadata_for_deparser_t 1398 | eg_intr_dprsr_md 1399 | ) { 1400 | 1401 | apply { 1402 | pkt.emit(hdr.ethernet); 1403 | pkt.emit(hdr.ipv4); 1404 | pkt.emit(hdr.tcp); 1405 | pkt.emit(hdr.class); 1406 | } 1407 | } 1408 | 1409 | Pipeline(SwitchIngressParser(), 1410 | SwitchIngress(), 1411 | SwitchIngressDeparser(), 1412 | SwitchEgressParser(), 1413 | SwitchEgress(), 1414 | SwitchEgressDeparser()) pipe; 1415 | 1416 | Switch(pipe) main; 1417 | -------------------------------------------------------------------------------- /leo/resource-model.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | def leo_model(alu_config, is_sram, transient, log=False): 4 | num_alu_layers = len(alu_config) 5 | single_table_sizes = [] 6 | 7 | total_size = 0 8 | curr_layer_result_combos = 1 9 | prev_layer_tcam = 1 10 | curr_layer_tcam = 1 11 | 12 | if log: 13 | print('{:>12} {:>12} {:>12}'.format('Layer #', 'Single Table Size', 'Total Layer Size')) 14 | for l in range(1, num_alu_layers + 2): 15 | if l == num_alu_layers + 1: 16 | num_mux_next_layer = 1 17 | else: 18 | num_mux_next_layer = alu_config[l - 1] 19 | 20 | if l > 1: 21 | curr_layer_tcam = alu_config[l - 2] + 1 22 | if is_sram: 23 | curr_layer_result_combos = 2 ** alu_config[l - 2] 24 | else: 25 | curr_layer_result_combos = curr_layer_tcam 26 | 27 | single_table_size = curr_layer_result_combos * prev_layer_tcam 28 | layer_size = single_table_size * num_mux_next_layer 29 | if transient: 30 | layer_size = layer_size * 2 31 | single_table_size = single_table_size * 2 32 | 33 | total_size += layer_size 34 | 35 | single_table_sizes.append(single_table_size) 36 | if log: 37 | print('{:>12} {:>12} {:>12}'.format(l, single_table_size, layer_size)) 38 | 39 | prev_layer_tcam = curr_layer_tcam * prev_layer_tcam 40 | 41 | if log: 42 | print('Total Size:', total_size) 43 | return single_table_sizes 44 | 45 | # Rules in layer i of LEO 46 | def R_i(i, L, R, K): 47 | if i == 1: 48 | return 1 49 | if L != 0: 50 | return min(L, R[i-1] * (K[i] + 1)) 51 | else: 52 | return R[i-1] * (K[i] + 1) 53 | 54 | def args_type_for_number_list(arg): 55 | try: 56 | return [int(num) for num in arg.split(',')] 57 | except ValueError: 58 | raise argparse.ArgumentTypeError('Invalid list of integers: "{}"'.format(arg)) 59 | 60 | if __name__ == '__main__': 61 | parser = argparse.ArgumentParser( 62 | description='This program prints out a breakdown of the table size in each compute Layer of Leo.') 63 | 64 | grouped_args = parser.add_mutually_exclusive_group(required=True) 65 | grouped_args.add_argument('--sram', action='store_true', help='Calculate memory usage for SRAM.') 66 | grouped_args.add_argument('--tcam', action='store_true', help='Calculate memory usage for TCAM.') 67 | 68 | parser.add_argument('--transient', action='store_true', help='Calculate memory use including the additional cost of support transient states during runtime updates.') 69 | parser.add_argument('--muxed_alu_config', type=args_type_for_number_list, required=True, help='A comma-separated list of integers representing the number of "Multiplexed ALUs" in each layer. E.g.: 3,3,1 represents a tree where 3 nodes (2 levels) are multiplexed in the first layer, 3 nodes (2 levels) are muxed in the second layer, and 1 node (1 level) is muxed in the third layer. A fourth leaf layer is automatically added.') 70 | args = parser.parse_args() 71 | 72 | if args.tcam: 73 | leo_model(args.muxed_alu_config, False, args.transient, True) 74 | elif args.sram: 75 | leo_model(args.muxed_alu_config, True, args.transient, True) 76 | 77 | # R = [1] 78 | # K = [0,3,3,3,3,3] 79 | # LEAF_LIMIT = 0 80 | 81 | # print('ALU config K =', K[1:]) 82 | # print('Leaf Limit L =', LEAF_LIMIT) 83 | # print('{:>12} {:>12} {:>12}'.format('i', 'R_i / TCAM', 'SRAM')) 84 | 85 | # for i in range(1, len(K)): 86 | # R_i_val = R_i(i, LEAF_LIMIT, R, K) 87 | # SRAM = R_i(i-1, LEAF_LIMIT, R, K) * 2 ** (K[i-1]) 88 | # print('{:>12} {:>12} {:>12}'.format(i, R_i_val, SRAM)) 89 | # R.append(R_i_val) --------------------------------------------------------------------------------