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  }