1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "packet_dependency.h"
18
19 #include <algorithm>
20 #include <list>
21 #include <set>
22
PacketDependency(const ParentDef * root)23 PacketDependency::PacketDependency(const ParentDef* root) {
24 std::map<std::string, std::set<std::string>> initial_parse_and_match_fields;
25 std::vector<std::string> available_fields;
26 CollectInitialParseAndMatchFields(root, initial_parse_and_match_fields);
27 FinalizeParseAndMatchFields(root, initial_parse_and_match_fields, available_fields);
28 }
29
GetDependencies(const std::string & packet_name)30 std::vector<std::string>& PacketDependency::GetDependencies(const std::string& packet_name) {
31 return dependencies[packet_name];
32 }
33
GetChildrenDependencies(const std::string & packet_name)34 std::vector<std::string>& PacketDependency::GetChildrenDependencies(
35 const std::string& packet_name) {
36 return children_dependencies[packet_name];
37 }
38
CollectInitialParseAndMatchFields(const ParentDef * parent,std::map<std::string,std::set<std::string>> & initial_parse_and_match_fields) const39 std::set<std::string> PacketDependency::CollectInitialParseAndMatchFields(
40 const ParentDef* parent,
41 std::map<std::string, std::set<std::string>>& initial_parse_and_match_fields) const {
42 // Case Leaf Packet: Return all of its constraints
43 if (parent->children_.empty()) {
44 auto constraints = parent->GetAllConstraints();
45 auto constraints_set = std::set<std::string>{};
46 for (auto& c : constraints) {
47 constraints_set.insert(c.first);
48 }
49 return constraints_set;
50 }
51
52 auto children_constraints = std::set<std::string>{};
53 auto parent_constraints = parent->GetAllConstraints();
54 auto parent_fields = parent->fields_;
55
56 for (const auto child : parent->children_) {
57 auto constraints = CollectInitialParseAndMatchFields(child, initial_parse_and_match_fields);
58 auto child_only_constraints = std::set<std::string>{};
59 for (auto c : constraints) {
60 // __PARENT__
61 // c1/ c2| \c3
62 // / | \.
63 // CH1 CH2 CH3
64 // c4|
65 // |
66 // CH11
67 // GetAllConstraints on leaf packet CH11 will return (C4, c1)
68 // GetAllConstraints on packet CH1 will return C1
69 // Thus CH11 only constraint is: (C4, C1) - (C1) => (C4)
70 if (parent_constraints.find(c) == parent_constraints.end()) {
71 child_only_constraints.insert(c);
72 }
73 // If the constraint can be satisfied by the immediate parent, no need to accumulate it
74 if (parent_fields.GetField(c) != nullptr) {
75 continue;
76 }
77 // Accumulate constraints from all the children so parent packet can accurately
78 // figure out which constraints it should be getting from its parents.
79 children_constraints.insert(c);
80 }
81 // child_only_constraints contains the variables required to be passed in when calling parse
82 initial_parse_and_match_fields[child->name_] = child_only_constraints;
83 }
84 return children_constraints;
85 }
86
FinalizeParseAndMatchFields(const ParentDef * parent,std::map<std::string,std::set<std::string>> & initial_parse_and_match_fields,std::vector<std::string> & available_fields)87 void PacketDependency::FinalizeParseAndMatchFields(
88 const ParentDef* parent,
89 std::map<std::string, std::set<std::string>>& initial_parse_and_match_fields,
90 std::vector<std::string>& available_fields) {
91 // Root does not have any constraints on anything
92 if (parent->parent_ == nullptr) {
93 dependencies[parent->name_] = std::vector<std::string>{};
94 children_dependencies[parent->name_] = std::vector<std::string>{};
95 }
96
97 // Collect the available fields, required to fix the order of pass and match vectors
98 for (auto& pf : parent->fields_) {
99 available_fields.push_back(pf->GetName());
100 }
101
102 auto children_constraints_to_me = std::set<std::string>{};
103 children_dependencies[parent->name_] = std::vector<std::string>{};
104
105 // Accumulate direct constraints from all the children to parent
106 // __PARENT__
107 // c1/ c2| \c3
108 // / | \.
109 // CH1 CH2 CH3
110 // c4|
111 // |
112 // CH11
113 // For this case: children_constraints_to_me = (c1, c2, c3)
114 for (auto& child : parent->children_) {
115 for (auto pcons : child->parent_constraints_) {
116 children_constraints_to_me.insert(pcons.first);
117 }
118 }
119
120 // If children constraints to the parent are (c1, c2, c3) and so far parent has
121 // fields (c1, c2) available, then parent will match its children on (c1, c2)
122 for (auto avf : available_fields) {
123 if (children_constraints_to_me.find(avf) != children_constraints_to_me.end()) {
124 auto& match_variables = children_dependencies[parent->name_];
125 if (std::find(match_variables.begin(), match_variables.end(), avf) == match_variables.end()) {
126 match_variables.push_back(avf);
127 }
128 }
129 }
130
131 for (auto& child : parent->children_) {
132 auto child_initial_parse_params = initial_parse_and_match_fields[child->name_];
133 auto child_actual_parse_params = std::vector<std::string>{};
134
135 // Remove all the params from parse method of this child
136 // if these variables are the ones parent will match its children.
137 for (auto pcons : child->parent_constraints_) {
138 child_initial_parse_params.erase(pcons.first);
139 }
140
141 // Store unique vars from child_initial_parse_params to child_actual_parse_params
142 // in the same order as fields are defined in the packets
143 for (auto avf : available_fields) {
144 if (child_initial_parse_params.find(avf) != child_initial_parse_params.end()) {
145 child_actual_parse_params.push_back(avf);
146 }
147 }
148 dependencies[child->name_] = child_actual_parse_params;
149 FinalizeParseAndMatchFields(child, initial_parse_and_match_fields, available_fields);
150 }
151 }
152