github.com/imran-kn/cilium-fork@v1.6.9/pkg/envoy/sort.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package envoy 16 17 import ( 18 "sort" 19 20 "github.com/cilium/proxy/go/cilium/api" 21 envoy_api_v2_route "github.com/cilium/proxy/go/envoy/api/v2/route" 22 ) 23 24 // PortNetworkPolicySlice implements sort.Interface to sort a slice of 25 // *cilium.PortNetworkPolicy. 26 type PortNetworkPolicySlice []*cilium.PortNetworkPolicy 27 28 func (s PortNetworkPolicySlice) Len() int { 29 return len(s) 30 } 31 32 func (s PortNetworkPolicySlice) Less(i, j int) bool { 33 p1, p2 := s[i], s[j] 34 35 switch { 36 case p1.Protocol < p2.Protocol: 37 return true 38 case p1.Protocol > p2.Protocol: 39 return false 40 } 41 42 switch { 43 case p1.Port < p2.Port: 44 return true 45 case p1.Port > p2.Port: 46 return false 47 } 48 49 rules1, rules2 := p1.Rules, p2.Rules 50 switch { 51 case len(rules1) < len(rules2): 52 return true 53 case len(rules1) > len(rules2): 54 return false 55 } 56 // Assuming that the slices are sorted. 57 for idx := range rules1 { 58 r1, r2 := rules1[idx], rules2[idx] 59 switch { 60 case PortNetworkPolicyRuleLess(r1, r2): 61 return true 62 case PortNetworkPolicyRuleLess(r2, r1): 63 return false 64 } 65 } 66 67 // Elements are equal. 68 return false 69 } 70 71 func (s PortNetworkPolicySlice) Swap(i, j int) { 72 s[i], s[j] = s[j], s[i] 73 } 74 75 // SortPortNetworkPolicies sorts the given slice. 76 func SortPortNetworkPolicies(policies []*cilium.PortNetworkPolicy) { 77 sort.Sort(PortNetworkPolicySlice(policies)) 78 } 79 80 // PortNetworkPolicyRuleSlice implements sort.Interface to sort a slice of 81 // *cilium.PortNetworkPolicyRuleSlice. 82 type PortNetworkPolicyRuleSlice []*cilium.PortNetworkPolicyRule 83 84 // PortNetworkPolicyRuleLess reports whether the r1 rule should sort before 85 // the r2 rule. 86 // L3-L4-only rules are less than L7 rules. 87 func PortNetworkPolicyRuleLess(r1, r2 *cilium.PortNetworkPolicyRule) bool { 88 // TODO: Support Kafka. 89 90 http1, http2 := r1.GetHttpRules(), r2.GetHttpRules() 91 switch { 92 case http1 == nil && http2 != nil: 93 return true 94 case http1 != nil && http2 == nil: 95 return false 96 } 97 98 if http1 != nil && http2 != nil { 99 httpRules1, httpRules2 := http1.HttpRules, http2.HttpRules 100 switch { 101 case len(httpRules1) < len(httpRules2): 102 return true 103 case len(httpRules1) > len(httpRules2): 104 return false 105 } 106 // Assuming that the slices are sorted. 107 for idx := range httpRules1 { 108 httpRule1, httpRule2 := httpRules1[idx], httpRules2[idx] 109 switch { 110 case HTTPNetworkPolicyRuleLess(httpRule1, httpRule2): 111 return true 112 case HTTPNetworkPolicyRuleLess(httpRule2, httpRule1): 113 return false 114 } 115 } 116 } 117 118 remotePolicies1, remotePolicies2 := r1.RemotePolicies, r2.RemotePolicies 119 switch { 120 case len(remotePolicies1) < len(remotePolicies2): 121 return true 122 case len(remotePolicies1) > len(remotePolicies2): 123 return false 124 } 125 // Assuming that the slices are sorted. 126 for idx := range remotePolicies1 { 127 p1, p2 := remotePolicies1[idx], remotePolicies2[idx] 128 switch { 129 case p1 < p2: 130 return true 131 case p1 > p2: 132 return false 133 } 134 } 135 136 // Elements are equal. 137 return false 138 } 139 140 func (s PortNetworkPolicyRuleSlice) Len() int { 141 return len(s) 142 } 143 144 func (s PortNetworkPolicyRuleSlice) Less(i, j int) bool { 145 return PortNetworkPolicyRuleLess(s[i], s[j]) 146 } 147 148 func (s PortNetworkPolicyRuleSlice) Swap(i, j int) { 149 s[i], s[j] = s[j], s[i] 150 } 151 152 // SortPortNetworkPolicyRules sorts the given slice. 153 func SortPortNetworkPolicyRules(rules []*cilium.PortNetworkPolicyRule) { 154 sort.Sort(PortNetworkPolicyRuleSlice(rules)) 155 } 156 157 // HTTPNetworkPolicyRuleSlice implements sort.Interface to sort a slice of 158 // *cilium.HttpNetworkPolicyRule. 159 type HTTPNetworkPolicyRuleSlice []*cilium.HttpNetworkPolicyRule 160 161 // HTTPNetworkPolicyRuleLess reports whether the r1 rule should sort before the 162 // r2 rule. 163 func HTTPNetworkPolicyRuleLess(r1, r2 *cilium.HttpNetworkPolicyRule) bool { 164 headers1, headers2 := r1.Headers, r2.Headers 165 switch { 166 case len(headers1) < len(headers2): 167 return true 168 case len(headers1) > len(headers2): 169 return false 170 } 171 // Assuming that the slices are sorted. 172 for idx := range headers1 { 173 header1, header2 := headers1[idx], headers2[idx] 174 switch { 175 case HeaderMatcherLess(header1, header2): 176 return true 177 case HeaderMatcherLess(header2, header1): 178 return false 179 } 180 } 181 182 // Elements are equal. 183 return false 184 } 185 186 func (s HTTPNetworkPolicyRuleSlice) Len() int { 187 return len(s) 188 } 189 190 func (s HTTPNetworkPolicyRuleSlice) Less(i, j int) bool { 191 return HTTPNetworkPolicyRuleLess(s[i], s[j]) 192 } 193 194 func (s HTTPNetworkPolicyRuleSlice) Swap(i, j int) { 195 s[i], s[j] = s[j], s[i] 196 } 197 198 // SortHTTPNetworkPolicyRules sorts the given slice. 199 func SortHTTPNetworkPolicyRules(rules []*cilium.HttpNetworkPolicyRule) { 200 sort.Sort(HTTPNetworkPolicyRuleSlice(rules)) 201 } 202 203 // HeaderMatcherSlice implements sort.Interface to sort a slice of 204 // *envoy_api_v2_route.HeaderMatcher. 205 type HeaderMatcherSlice []*envoy_api_v2_route.HeaderMatcher 206 207 // HeaderMatcherLess reports whether the m1 matcher should sort before the m2 208 // matcher. 209 func HeaderMatcherLess(m1, m2 *envoy_api_v2_route.HeaderMatcher) bool { 210 switch { 211 case m1.Name < m2.Name: 212 return true 213 case m1.Name > m2.Name: 214 return false 215 } 216 217 // Compare the header_match_specifier oneof field, by comparing each 218 // possible field in the oneof individually: 219 // - exactMatch 220 // - regexMatch 221 // - rangeMatch 222 // - presentMatch 223 // - prefixMatch 224 // - suffixMatch 225 // Use the getters to access the fields and return zero values when they 226 // are not set. 227 228 s1 := m1.GetExactMatch() 229 s2 := m2.GetExactMatch() 230 switch { 231 case s1 < s2: 232 return true 233 case s1 > s2: 234 return false 235 } 236 237 s1 = m1.GetRegexMatch() 238 s2 = m2.GetRegexMatch() 239 switch { 240 case s1 < s2: 241 return true 242 case s1 > s2: 243 return false 244 } 245 246 rm1 := m1.GetRangeMatch() 247 rm2 := m2.GetRangeMatch() 248 switch { 249 case rm1 == nil && rm2 != nil: 250 return true 251 case rm1 != nil && rm2 == nil: 252 return false 253 case rm1 != nil && rm2 != nil: 254 switch { 255 case rm1.Start < rm2.Start: 256 return true 257 case rm1.Start > rm2.Start: 258 return false 259 } 260 switch { 261 case rm1.End < rm2.End: 262 return true 263 case rm1.End > rm2.End: 264 return false 265 } 266 } 267 268 switch { 269 case !m1.GetPresentMatch() && m2.GetPresentMatch(): 270 return true 271 case m1.GetPresentMatch() && !m2.GetPresentMatch(): 272 return false 273 } 274 275 s1 = m1.GetPrefixMatch() 276 s2 = m2.GetPrefixMatch() 277 switch { 278 case s1 < s2: 279 return true 280 case s1 > s2: 281 return false 282 } 283 284 s1 = m1.GetSuffixMatch() 285 s2 = m2.GetSuffixMatch() 286 switch { 287 case s1 < s2: 288 return true 289 case s1 > s2: 290 return false 291 } 292 293 switch { 294 case !m1.InvertMatch && m2.InvertMatch: 295 return true 296 case m1.InvertMatch && !m2.InvertMatch: 297 return false 298 } 299 300 // Elements are equal. 301 return false 302 } 303 304 func (s HeaderMatcherSlice) Len() int { 305 return len(s) 306 } 307 308 func (s HeaderMatcherSlice) Less(i, j int) bool { 309 return HeaderMatcherLess(s[i], s[j]) 310 } 311 312 func (s HeaderMatcherSlice) Swap(i, j int) { 313 s[i], s[j] = s[j], s[i] 314 } 315 316 // SortHeaderMatchers sorts the given slice. 317 func SortHeaderMatchers(headers []*envoy_api_v2_route.HeaderMatcher) { 318 sort.Sort(HeaderMatcherSlice(headers)) 319 }