Repository: cilium/cilium
Pull request #13468 (2020-10-08 15:46:53)

bpf: Remove duplicate command from init.sh
`setup_dev` already brings the interface up, so there is no need to repeat that command.

pchaigno: test-me-please
pchaigno: test-me-please

Patch:
diff --git a/Documentation/cmdref/cilium_service_update.md b/Documentation/cmdref/cilium_service_update.md
index e76c3832c6..849df74b6f 100644
--- a/Documentation/cmdref/cilium_service_update.md
+++ b/Documentation/cmdref/cilium_service_update.md
@@ -26,6 +26,7 @@ cilium service update [flags]
       --k8s-node-port               Set service as a k8s NodePort
       --k8s-traffic-policy string   Set service with k8s externalTrafficPolicy as {Local,Cluster} (default "Cluster")
       --local-redirect              Set service as Local Redirect
+      --protocol string             Protocol for service (e.g. TCP, UDP) (default "tcp")
 ```
 
 ### Options inherited from parent commands
diff --git a/Documentation/gettingstarted/kubeproxy-free.rst b/Documentation/gettingstarted/kubeproxy-free.rst
index 057a3ba82a..81ac219e98 100644
--- a/Documentation/gettingstarted/kubeproxy-free.rst
+++ b/Documentation/gettingstarted/kubeproxy-free.rst
@@ -224,16 +224,16 @@ port ``31940`` (one for each of devices ``eth0`` and ``eth1``):
 .. parsed-literal::
 
     kubectl exec -it -n kube-system cilium-fmh8d -- cilium service list
-    ID   Frontend               Service Type   Backend                    
+    ID   Frontend                   Service Type   Backend                    
     [...]
-    4    10.104.239.135:80      ClusterIP      1 => 10.217.0.107:80       
-                                               2 => 10.217.0.149:80       
-    5    0.0.0.0:31940          NodePort       1 => 10.217.0.107:80       
-                                               2 => 10.217.0.149:80       
-    6    192.168.178.29:31940   NodePort       1 => 10.217.0.107:80       
-                                               2 => 10.217.0.149:80       
-    7    172.16.0.29:31940      NodePort       1 => 10.217.0.107:80       
-                                               2 => 10.217.0.149:80       
+    4    10.104.239.135:80/TCP      ClusterIP      1 => 10.217.0.107:80/TCP
+                                                   2 => 10.217.0.149:80/TCP
+    5    0.0.0.0:31940/TCP          NodePort       1 => 10.217.0.107:80/TCP
+                                                   2 => 10.217.0.149:80/TCP
+    6    192.168.178.29:31940/TCP   NodePort       1 => 10.217.0.107:80/TCP
+                                                   2 => 10.217.0.149:80/TCP
+    7    172.16.0.29:31940/TCP      NodePort       1 => 10.217.0.107:80/TCP
+                                                   2 => 10.217.0.149:80/TCP
 
 At the same time we can inspect through ``iptables`` in the host namespace
 that no ``iptables`` rule for the service is present:
diff --git a/Documentation/gettingstarted/minikube-install.rst b/Documentation/gettingstarted/minikube-install.rst
index 2e001fa1d9..09f238b1fd 100644
--- a/Documentation/gettingstarted/minikube-install.rst
+++ b/Documentation/gettingstarted/minikube-install.rst
@@ -26,7 +26,7 @@
 ::
 
      # Only available for minikube >= v1.12.1
-     minikube start --network-plugin=cilium --memory=4096
+     minikube start --cni=cilium --memory=4096
 
 .. note::
 
diff --git a/Documentation/gettingstarted/tls-visibility.rst b/Documentation/gettingstarted/tls-visibility.rst
index fce55911c6..f84962e070 100644
--- a/Documentation/gettingstarted/tls-visibility.rst
+++ b/Documentation/gettingstarted/tls-visibility.rst
@@ -101,17 +101,17 @@ requires four primary steps:
 1) Create an internal certificate authority by generating a CA private key and CA certificate.
 
 2) For any destination where TLS inspection is desired (e.g., artii.herokuapp.com in the example below),
-generate a private key and certificate signing request with a common name that matches the destination DNS
-name.
+   generate a private key and certificate signing request with a common name that matches the destination DNS
+   name.
 
 3) Use the CA private key to create a signed certificate.
 
 4) Ensure that all clients where TLS inspection is have the CA certificate installed so that they will
-trust all certificates signed by that CA.
+   trust all certificates signed by that CA.
 
 5) Given that Cilium will be terminating the initial TLS connection from the
-client and creating a new TLS connection to the destination, Cilium must be told the set of CAs that it
-should trust when validating the new TLS connection to the destination service.
+   client and creating a new TLS connection to the destination, Cilium must be told the set of CAs that it
+   should trust when validating the new TLS connection to the destination service.
 
 .. note::
 
@@ -247,7 +247,7 @@ certificate bundle and use it to validate outgoing TLS connections.
 
 .. parsed-literal::
 
-    $ kubectl create secret generic tls-orig-data -n kube-system --from-file=./ca-certificates.crt
+    $ kubectl create secret generic tls-orig-data -n kube-system --from-file=ca.crt=./ca-certificates.crt
 
 
 Apply DNS and TLS-aware Egress Policy
@@ -263,15 +263,16 @@ of communication between the ``mediabot`` pod to ``artii.herokuapp.com``.
 .. literalinclude:: ../../examples/kubernetes-tls-inspection/l7-visibility-tls.yaml
 
 Let's take a closer look at the policy:
+
 * The ``endpointSelector`` means that this policy will only apply to pods with labels ``class: mediabot, org:empire`` to have the egress access.
 * The first egress section uses ``toFQDNs: matchName`` specification to allow TCP port 443 egress to ``artii.herokuapp.com``.
 * The ``http`` section below the toFQDNs rule
-indicates that such connections should be parsed as HTTP, with a policy of ``{}`` which will allow all requests.
+  indicates that such connections should be parsed as HTTP, with a policy of ``{}`` which will allow all requests.
 * The ``terminatingTLS`` and ``originatingTLS`` sections indicate that TLS interception should be used to terminate the initial TLS connection
-from mediabot and initiate a new out-bound TLS connection to ``artii.herokuapp.com``.
+  from mediabot and initiate a new out-bound TLS connection to ``artii.herokuapp.com``.
 * The second egress section allows ``mediabot`` pods to access ``kube-dns`` service. Note that
-``rules: dns`` instructs Cilium to inspect and allow DNS lookups matching specified patterns.
-In this case, inspect and allow all DNS queries.
+  ``rules: dns`` instructs Cilium to inspect and allow DNS lookups matching specified patterns.
+  In this case, inspect and allow all DNS queries.
 
 Note that with this policy the ``mediabot`` doesn't have access to any internal cluster service other than ``kube-dns``
 and will have no access to any other external destinations either. Refer to :ref:`Network Policy`
@@ -316,9 +317,8 @@ Looking back at the cilium monitor window, you will see each individual HTTP req
 
 .. parsed-literal::
 
-    -> Request http from 1975 ([k8s:app=public-service k8s:io.cilium.k8s.policy.cluster=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=tenant-a]) to 0 ([reserved:world]), identity 56418->2, verdict Forwarded GET https://www.lyft.com/privacy => 0
-    -> Response http to 1975 ([k8s:app=public-service k8s:io.cilium.k8s.policy.cluster=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=tenant-a]) from 0 ([reserved:world]), identity 56418->2, verdict Forwarded GET https://www.lyft.com/privacy => 200
-
+    -> Request http from 2585 ([k8s:class=mediabot k8s:org=empire k8s:io.kubernetes.pod.namespace=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.cilium.k8s.policy.cluster=default]) to 0 ([reserved:world]), identity 24948->2, verdict Forwarded GET https://artii.herokuapp.com/fonts_list => 0
+    -> Response http to 2585 ([k8s:io.kubernetes.pod.namespace=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.cilium.k8s.policy.cluster=default k8s:class=mediabot k8s:org=empire]) from 0 ([reserved:world]), identity 24948->2, verdict Forwarded GET https://artii.herokuapp.com/fonts_list => 200
 
 Refer to :ref:`l4_policy` and :ref:`l7_policy` to learn more about Cilium L4 and L7 network policies.
 
@@ -329,4 +329,5 @@ Clean-up
 
    $ kubectl delete -f \ |SCM_WEB|\/examples/kubernetes-dns/dns-sw-app.yaml
    $ kubectl delete cnp l7-visibility-tls
-
+   $ kubectl delete secret -n kube-system tls-orig-data
+   $ kubectl delete secret -n kube-system artii-tls-data
diff --git a/USERS.md b/USERS.md
index 4976476fcb..62f835b0de 100644
--- a/USERS.md
+++ b/USERS.md
@@ -60,6 +60,11 @@ Users (Alphabetically)
       U: Networking, NetworkPolicy, Services, IPVLAN
       L: https://www.alibabacloud.com/blog/how-does-alibaba-cloud-build-high-performance-cloud-native-pod-networks-in-production-environments_596590
 
+    * N: Canonical
+      D: Canonical's Kubernetes distribution microk8s uses Cilium as CNI plugin
+      U: Networking, NetworkPolicy, and Kubernetes services
+      L: https://microk8s.io/
+
     * N: CENGN - Centre of Excellence in Next Generation Networks
       D: CENGN is using Cilium in multiple clusters including production and development clusters (self-hosted k8s, On-premises)
       U: L3/L4/L7 network policies, Monitoring via Prometheus metrics & Hubble
diff --git a/api/v1/flow/flow.pb.go b/api/v1/flow/flow.pb.go
index 08c4e8e979..2969778663 100644
--- a/api/v1/flow/flow.pb.go
+++ b/api/v1/flow/flow.pb.go
@@ -329,6 +329,203 @@ func (Verdict) EnumDescriptor() ([]byte, []int) {
 	return file_flow_flow_proto_rawDescGZIP(), []int{4}
 }
 
+// Taken from pkg/monitor/api/drop.go. Note that non-drop reasons (i.e. values
+// less than api.DropMin) are not used here.
+type DropReason int32
+
+const (
+	// non-drop reasons
+	DropReason_DROP_REASON_UNKNOWN DropReason = 0
+	// drop reasons
+	DropReason_INVALID_SOURCE_MAC                                    DropReason = 130
+	DropReason_INVALID_DESTINATION_MAC                               DropReason = 131
+	DropReason_INVALID_SOURCE_IP                                     DropReason = 132
+	DropReason_POLICY_DENIED                                         DropReason = 133
+	DropReason_INVALID_PACKET_DROPPED                                DropReason = 134
+	DropReason_CT_TRUNCATED_OR_INVALID_HEADER                        DropReason = 135
+	DropReason_CT_MISSING_TCP_ACK_FLAG                               DropReason = 136
+	DropReason_CT_UNKNOWN_L4_PROTOCOL                                DropReason = 137
+	DropReason_CT_CANNOT_CREATE_ENTRY_FROM_PACKET                    DropReason = 138
+	DropReason_UNSUPPORTED_L3_PROTOCOL                               DropReason = 139
+	DropReason_MISSED_TAIL_CALL                                      DropReason = 140
+	DropReason_ERROR_WRITING_TO_PACKET                               DropReason = 141
+	DropReason_UNKNOWN_L4_PROTOCOL                                   DropReason = 142
+	DropReason_UNKNOWN_ICMPV4_CODE                                   DropReason = 143
+	DropReason_UNKNOWN_ICMPV4_TYPE                                   DropReason = 144
+	DropReason_UNKNOWN_ICMPV6_CODE                                   DropReason = 145
+	DropReason_UNKNOWN_ICMPV6_TYPE                                   DropReason = 146
+	DropReason_ERROR_RETRIEVING_TUNNEL_KEY                           DropReason = 147
+	DropReason_ERROR_RETRIEVING_TUNNEL_OPTIONS                       DropReason = 148
+	DropReason_INVALID_GENEVE_OPTION                                 DropReason = 149
+	DropReason_UNKNOWN_L3_TARGET_ADDRESS                             DropReason = 150
+	DropReason_STALE_OR_UNROUTABLE_IP                                DropReason = 151
+	DropReason_NO_MATCHING_LOCAL_CONTAINER_FOUND                     DropReason = 152
+	DropReason_ERROR_WHILE_CORRECTING_L3_CHECKSUM                    DropReason = 153
+	DropReason_ERROR_WHILE_CORRECTING_L4_CHECKSUM                    DropReason = 154
+	DropReason_CT_MAP_INSERTION_FAILED                               DropReason = 155
+	DropReason_INVALID_IPV6_EXTENSION_HEADER                         DropReason = 156
+	DropReason_IP_FRAGMENTATION_NOT_SUPPORTED                        DropReason = 157
+	DropReason_SERVICE_BACKEND_NOT_FOUND                             DropReason = 158
+	DropReason_NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT                   DropReason = 160
+	DropReason_FAILED_TO_INSERT_INTO_PROXYMAP                        DropReason = 161
+	DropReason_REACHED_EDT_RATE_LIMITING_DROP_HORIZON                DropReason = 162
+	DropReason_UNKNOWN_CONNECTION_TRACKING_STATE                     DropReason = 163
+	DropReason_LOCAL_HOST_IS_UNREACHABLE                             DropReason = 164
+	DropReason_NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION DropReason = 165
+	DropReason_UNSUPPORTED_L2_PROTOCOL                               DropReason = 166
+	DropReason_NO_MAPPING_FOR_NAT_MASQUERADE                         DropReason = 167
+	DropReason_UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE               DropReason = 168
+	DropReason_FIB_LOOKUP_FAILED                                     DropReason = 169
+	DropReason_ENCAPSULATION_TRAFFIC_IS_PROHIBITED                   DropReason = 170
+	DropReason_INVALID_IDENTITY                                      DropReason = 171
+	DropReason_UNKNOWN_SENDER                                        DropReason = 172
+	DropReason_NAT_NOT_NEEDED                                        DropReason = 173
+	DropReason_IS_A_CLUSTERIP                                        DropReason = 174
+	DropReason_FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND             DropReason = 175
+	DropReason_FORBIDDEN_ICMPV6_MESSAGE                              DropReason = 176
+	DropReason_DENIED_BY_LB_SRC_RANGE_CHECK                          DropReason = 177
+	DropReason_SOCKET_LOOKUP_FAILED                                  DropReason = 178
+	DropReason_SOCKET_ASSIGN_FAILED                                  DropReason = 179
+	DropReason_PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL          DropReason = 180
+)
+
+// Enum value maps for DropReason.
+var (
+	DropReason_name = map[int32]string{
+		0:   "DROP_REASON_UNKNOWN",
+		130: "INVALID_SOURCE_MAC",
+		131: "INVALID_DESTINATION_MAC",
+		132: "INVALID_SOURCE_IP",
+		133: "POLICY_DENIED",
+		134: "INVALID_PACKET_DROPPED",
+		135: "CT_TRUNCATED_OR_INVALID_HEADER",
+		136: "CT_MISSING_TCP_ACK_FLAG",
+		137: "CT_UNKNOWN_L4_PROTOCOL",
+		138: "CT_CANNOT_CREATE_ENTRY_FROM_PACKET",
+		139: "UNSUPPORTED_L3_PROTOCOL",
+		140: "MISSED_TAIL_CALL",
+		141: "ERROR_WRITING_TO_PACKET",
+		142: "UNKNOWN_L4_PROTOCOL",
+		143: "UNKNOWN_ICMPV4_CODE",
+		144: "UNKNOWN_ICMPV4_TYPE",
+		145: "UNKNOWN_ICMPV6_CODE",
+		146: "UNKNOWN_ICMPV6_TYPE",
+		147: "ERROR_RETRIEVING_TUNNEL_KEY",
+		148: "ERROR_RETRIEVING_TUNNEL_OPTIONS",
+		149: "INVALID_GENEVE_OPTION",
+		150: "UNKNOWN_L3_TARGET_ADDRESS",
+		151: "STALE_OR_UNROUTABLE_IP",
+		152: "NO_MATCHING_LOCAL_CONTAINER_FOUND",
+		153: "ERROR_WHILE_CORRECTING_L3_CHECKSUM",
+		154: "ERROR_WHILE_CORRECTING_L4_CHECKSUM",
+		155: "CT_MAP_INSERTION_FAILED",
+		156: "INVALID_IPV6_EXTENSION_HEADER",
+		157: "IP_FRAGMENTATION_NOT_SUPPORTED",
+		158: "SERVICE_BACKEND_NOT_FOUND",
+		160: "NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT",
+		161: "FAILED_TO_INSERT_INTO_PROXYMAP",
+		162: "REACHED_EDT_RATE_LIMITING_DROP_HORIZON",
+		163: "UNKNOWN_CONNECTION_TRACKING_STATE",
+		164: "LOCAL_HOST_IS_UNREACHABLE",
+		165: "NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION",
+		166: "UNSUPPORTED_L2_PROTOCOL",
+		167: "NO_MAPPING_FOR_NAT_MASQUERADE",
+		168: "UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE",
+		169: "FIB_LOOKUP_FAILED",
+		170: "ENCAPSULATION_TRAFFIC_IS_PROHIBITED",
+		171: "INVALID_IDENTITY",
+		172: "UNKNOWN_SENDER",
+		173: "NAT_NOT_NEEDED",
+		174: "IS_A_CLUSTERIP",
+		175: "FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND",
+		176: "FORBIDDEN_ICMPV6_MESSAGE",
+		177: "DENIED_BY_LB_SRC_RANGE_CHECK",
+		178: "SOCKET_LOOKUP_FAILED",
+		179: "SOCKET_ASSIGN_FAILED",
+		180: "PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL",
+	}
+	DropReason_value = map[string]int32{
+		"DROP_REASON_UNKNOWN":                                   0,
+		"INVALID_SOURCE_MAC":                                    130,
+		"INVALID_DESTINATION_MAC":                               131,
+		"INVALID_SOURCE_IP":                                     132,
+		"POLICY_DENIED":                                         133,
+		"INVALID_PACKET_DROPPED":                                134,
+		"CT_TRUNCATED_OR_INVALID_HEADER":                        135,
+		"CT_MISSING_TCP_ACK_FLAG":                               136,
+		"CT_UNKNOWN_L4_PROTOCOL":                                137,
+		"CT_CANNOT_CREATE_ENTRY_FROM_PACKET":                    138,
+		"UNSUPPORTED_L3_PROTOCOL":                               139,
+		"MISSED_TAIL_CALL":                                      140,
+		"ERROR_WRITING_TO_PACKET":                               141,
+		"UNKNOWN_L4_PROTOCOL":                                   142,
+		"UNKNOWN_ICMPV4_CODE":                                   143,
+		"UNKNOWN_ICMPV4_TYPE":                                   144,
+		"UNKNOWN_ICMPV6_CODE":                                   145,
+		"UNKNOWN_ICMPV6_TYPE":                                   146,
+		"ERROR_RETRIEVING_TUNNEL_KEY":                           147,
+		"ERROR_RETRIEVING_TUNNEL_OPTIONS":                       148,
+		"INVALID_GENEVE_OPTION":                                 149,
+		"UNKNOWN_L3_TARGET_ADDRESS":                             150,
+		"STALE_OR_UNROUTABLE_IP":                                151,
+		"NO_MATCHING_LOCAL_CONTAINER_FOUND":                     152,
+		"ERROR_WHILE_CORRECTING_L3_CHECKSUM":                    153,
+		"ERROR_WHILE_CORRECTING_L4_CHECKSUM":                    154,
+		"CT_MAP_INSERTION_FAILED":                               155,
+		"INVALID_IPV6_EXTENSION_HEADER":                         156,
+		"IP_FRAGMENTATION_NOT_SUPPORTED":                        157,
+		"SERVICE_BACKEND_NOT_FOUND":                             158,
+		"NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT":                   160,
+		"FAILED_TO_INSERT_INTO_PROXYMAP":                        161,
+		"REACHED_EDT_RATE_LIMITING_DROP_HORIZON":                162,
+		"UNKNOWN_CONNECTION_TRACKING_STATE":                     163,
+		"LOCAL_HOST_IS_UNREACHABLE":                             164,
+		"NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION": 165,
+		"UNSUPPORTED_L2_PROTOCOL":                               166,
+		"NO_MAPPING_FOR_NAT_MASQUERADE":                         167,
+		"UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE":               168,
+		"FIB_LOOKUP_FAILED":                                     169,
+		"ENCAPSULATION_TRAFFIC_IS_PROHIBITED":                   170,
+		"INVALID_IDENTITY":                                      171,
+		"UNKNOWN_SENDER":                                        172,
+		"NAT_NOT_NEEDED":                                        173,
+		"IS_A_CLUSTERIP":                                        174,
+		"FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND":             175,
+		"FORBIDDEN_ICMPV6_MESSAGE":                              176,
+		"DENIED_BY_LB_SRC_RANGE_CHECK":                          177,
+		"SOCKET_LOOKUP_FAILED":                                  178,
+		"SOCKET_ASSIGN_FAILED":                                  179,
+		"PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL":          180,
+	}
+)
+
+func (x DropReason) Enum() *DropReason {
+	p := new(DropReason)
+	*p = x
+	return p
+}
+
+func (x DropReason) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DropReason) Descriptor() protoreflect.EnumDescriptor {
+	return file_flow_flow_proto_enumTypes[5].Descriptor()
+}
+
+func (DropReason) Type() protoreflect.EnumType {
+	return &file_flow_flow_proto_enumTypes[5]
+}
+
+func (x DropReason) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use DropReason.Descriptor instead.
+func (DropReason) EnumDescriptor() ([]byte, []int) {
+	return file_flow_flow_proto_rawDescGZIP(), []int{5}
+}
+
 type TrafficDirection int32
 
 const (
@@ -362,11 +559,11 @@ func (x TrafficDirection) String() string {
 }
 
 func (TrafficDirection) Descriptor() protoreflect.EnumDescriptor {
-	return file_flow_flow_proto_enumTypes[5].Descriptor()
+	return file_flow_flow_proto_enumTypes[6].Descriptor()
 }
 
 func (TrafficDirection) Type() protoreflect.EnumType {
-	return &file_flow_flow_proto_enumTypes[5]
+	return &file_flow_flow_proto_enumTypes[6]
 }
 
 func (x TrafficDirection) Number() protoreflect.EnumNumber {
@@ -375,7 +572,7 @@ func (x TrafficDirection) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use TrafficDirection.Descriptor instead.
 func (TrafficDirection) EnumDescriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{5}
+	return file_flow_flow_proto_rawDescGZIP(), []int{6}
 }
 
 // EventType are constants are based on the ones from <linux/perf_event.h>.
@@ -414,11 +611,11 @@ func (x EventType) String() string {
 }
 
 func (EventType) Descriptor() protoreflect.EnumDescriptor {
-	return file_flow_flow_proto_enumTypes[6].Descriptor()
+	return file_flow_flow_proto_enumTypes[7].Descriptor()
 }
 
 func (EventType) Type() protoreflect.EnumType {
-	return &file_flow_flow_proto_enumTypes[6]
+	return &file_flow_flow_proto_enumTypes[7]
 }
 
 func (x EventType) Number() protoreflect.EnumNumber {
@@ -427,7 +624,7 @@ func (x EventType) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use EventType.Descriptor instead.
 func (EventType) EnumDescriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{6}
+	return file_flow_flow_proto_rawDescGZIP(), []int{7}
 }
 
 type LostEventSource int32
@@ -469,11 +666,11 @@ func (x LostEventSource) String() string {
 }
 
 func (LostEventSource) Descriptor() protoreflect.EnumDescriptor {
-	return file_flow_flow_proto_enumTypes[7].Descriptor()
+	return file_flow_flow_proto_enumTypes[8].Descriptor()
 }
 
 func (LostEventSource) Type() protoreflect.EnumType {
-	return &file_flow_flow_proto_enumTypes[7]
+	return &file_flow_flow_proto_enumTypes[8]
 }
 
 func (x LostEventSource) Number() protoreflect.EnumNumber {
@@ -482,7 +679,7 @@ func (x LostEventSource) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use LostEventSource.Descriptor instead.
 func (LostEventSource) EnumDescriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{7}
+	return file_flow_flow_proto_rawDescGZIP(), []int{8}
 }
 
 type Flow struct {
@@ -493,6 +690,9 @@ type Flow struct {
 	Time    *timestamp.Timestamp `protobuf:"bytes,1,opt,name=time,proto3" json:"time,omitempty"`
 	Verdict Verdict              `protobuf:"varint,2,opt,name=verdict,proto3,enum=flow.Verdict" json:"verdict,omitempty"`
 	// only applicable to Verdict = DROPPED.
+	// deprecated in favor of drop_reason_desc.
+	//
+	// Deprecated: Do not use.
 	DropReason uint32 `protobuf:"varint,3,opt,name=drop_reason,json=dropReason,proto3" json:"drop_reason,omitempty"`
 	// l2
 	Ethernet *Ethernet `protobuf:"bytes,4,opt,name=ethernet,proto3" json:"ethernet,omitempty"`
@@ -525,6 +725,8 @@ type Flow struct {
 	PolicyMatchType uint32 `protobuf:"varint,23,opt,name=policy_match_type,json=policyMatchType,proto3" json:"policy_match_type,omitempty"`
 	// Only applicable to cilium trace notifications, blank for other types.
 	TraceObservationPoint TraceObservationPoint `protobuf:"varint,24,opt,name=trace_observation_point,json=traceObservationPoint,proto3,enum=flow.TraceObservationPoint" json:"trace_observation_point,omitempty"`
+	// only applicable to Verdict = DROPPED.
+	DropReasonDesc DropReason `protobuf:"varint,25,opt,name=drop_reason_desc,json=dropReasonDesc,proto3,enum=flow.DropReason" json:"drop_reason_desc,omitempty"`
 	// This is a temporary workaround to support summary field for pb.Flow without
 	// duplicating logic from the old parser. This field will be removed once we
 	// fully migrate to the new parser.
@@ -579,6 +781,7 @@ func (x *Flow) GetVerdict() Verdict {
 	return Verdict_VERDICT_UNKNOWN
 }
 
+// Deprecated: Do not use.
 func (x *Flow) GetDropReason() uint32 {
 	if x != nil {
 		return x.DropReason
@@ -705,6 +908,13 @@ func (x *Flow) GetTraceObservationPoint() TraceObservationPoint {
 	return TraceObservationPoint_UNKNOWN_POINT
 }
 
+func (x *Flow) GetDropReasonDesc() DropReason {
+	if x != nil {
+		return x.DropReasonDesc
+	}
+	return DropReason_DROP_REASON_UNKNOWN
+}
+
 // Deprecated: Do not use.
 func (x *Flow) GetSummary() string {
 	if x != nil {
@@ -1861,100 +2071,6 @@ func (x *FlowFilter) GetHttpPath() []string {
 	return nil
 }
 
-// Payload is the payload, i.e. the data the monitor returns.
-type Payload struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	// type is the event type perf returns.
-	Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=flow.EventType" json:"type,omitempty"`
-	// CPU is the CPU id for this event.
-	CPU int32 `protobuf:"varint,2,opt,name=CPU,proto3" json:"CPU,omitempty"`
-	// lost is the number of events lost for a given CPU.
-	Lost uint64 `protobuf:"varint,3,opt,name=lost,proto3" json:"lost,omitempty"`
-	// data is the sample data returned by perf.
-	Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
-	// time when the event was observed
-	Time *timestamp.Timestamp `protobuf:"bytes,5,opt,name=time,proto3" json:"time,omitempty"`
-	// the host name from which the payload was captured.
-	HostName string `protobuf:"bytes,6,opt,name=host_name,json=hostName,proto3" json:"host_name,omitempty"`
-}
-
-func (x *Payload) Reset() {
-	*x = Payload{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[14]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Payload) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Payload) ProtoMessage() {}
-
-func (x *Payload) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[14]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Payload.ProtoReflect.Descriptor instead.
-func (*Payload) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{14}
-}
-
-func (x *Payload) GetType() EventType {
-	if x != nil {
-		return x.Type
-	}
-	return EventType_UNKNOWN
-}
-
-func (x *Payload) GetCPU() int32 {
-	if x != nil {
-		return x.CPU
-	}
-	return 0
-}
-
-func (x *Payload) GetLost() uint64 {
-	if x != nil {
-		return x.Lost
-	}
-	return 0
-}
-
-func (x *Payload) GetData() []byte {
-	if x != nil {
-		return x.Data
-	}
-	return nil
-}
-
-func (x *Payload) GetTime() *timestamp.Timestamp {
-	if x != nil {
-		return x.Time
-	}
-	return nil
-}
-
-func (x *Payload) GetHostName() string {
-	if x != nil {
-		return x.HostName
-	}
-	return ""
-}
-
 // DNS flow. This is basically directly mapped from Cilium's LogRecordDNS:
 //     https://github.com/cilium/cilium/blob/04f3889d627774f79e56d14ddbc165b3169e2d01/pkg/proxy/accesslog/record.go#L264
 type DNS struct {
@@ -1987,7 +2103,7 @@ type DNS struct {
 func (x *DNS) Reset() {
 	*x = DNS{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[15]
+		mi := &file_flow_flow_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2000,7 +2116,7 @@ func (x *DNS) String() string {
 func (*DNS) ProtoMessage() {}
 
 func (x *DNS) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[15]
+	mi := &file_flow_flow_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2013,7 +2129,7 @@ func (x *DNS) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DNS.ProtoReflect.Descriptor instead.
 func (*DNS) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{15}
+	return file_flow_flow_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *DNS) GetQuery() string {
@@ -2084,7 +2200,7 @@ type HTTPHeader struct {
 func (x *HTTPHeader) Reset() {
 	*x = HTTPHeader{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[16]
+		mi := &file_flow_flow_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2097,7 +2213,7 @@ func (x *HTTPHeader) String() string {
 func (*HTTPHeader) ProtoMessage() {}
 
 func (x *HTTPHeader) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[16]
+	mi := &file_flow_flow_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2110,7 +2226,7 @@ func (x *HTTPHeader) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use HTTPHeader.ProtoReflect.Descriptor instead.
 func (*HTTPHeader) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{16}
+	return file_flow_flow_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *HTTPHeader) GetKey() string {
@@ -2144,7 +2260,7 @@ type HTTP struct {
 func (x *HTTP) Reset() {
 	*x = HTTP{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[17]
+		mi := &file_flow_flow_proto_msgTypes[16]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2157,7 +2273,7 @@ func (x *HTTP) String() string {
 func (*HTTP) ProtoMessage() {}
 
 func (x *HTTP) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[17]
+	mi := &file_flow_flow_proto_msgTypes[16]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2170,7 +2286,7 @@ func (x *HTTP) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use HTTP.ProtoReflect.Descriptor instead.
 func (*HTTP) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{17}
+	return file_flow_flow_proto_rawDescGZIP(), []int{16}
 }
 
 func (x *HTTP) GetCode() uint32 {
@@ -2225,7 +2341,7 @@ type Kafka struct {
 func (x *Kafka) Reset() {
 	*x = Kafka{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[18]
+		mi := &file_flow_flow_proto_msgTypes[17]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2238,7 +2354,7 @@ func (x *Kafka) String() string {
 func (*Kafka) ProtoMessage() {}
 
 func (x *Kafka) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[18]
+	mi := &file_flow_flow_proto_msgTypes[17]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2251,7 +2367,7 @@ func (x *Kafka) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Kafka.ProtoReflect.Descriptor instead.
 func (*Kafka) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{18}
+	return file_flow_flow_proto_rawDescGZIP(), []int{17}
 }
 
 func (x *Kafka) GetErrorCode() int32 {
@@ -2301,7 +2417,7 @@ type Service struct {
 func (x *Service) Reset() {
 	*x = Service{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[19]
+		mi := &file_flow_flow_proto_msgTypes[18]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2314,7 +2430,7 @@ func (x *Service) String() string {
 func (*Service) ProtoMessage() {}
 
 func (x *Service) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[19]
+	mi := &file_flow_flow_proto_msgTypes[18]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2327,7 +2443,7 @@ func (x *Service) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Service.ProtoReflect.Descriptor instead.
 func (*Service) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{19}
+	return file_flow_flow_proto_rawDescGZIP(), []int{18}
 }
 
 func (x *Service) GetName() string {
@@ -2363,7 +2479,7 @@ type LostEvent struct {
 func (x *LostEvent) Reset() {
 	*x = LostEvent{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_flow_flow_proto_msgTypes[20]
+		mi := &file_flow_flow_proto_msgTypes[19]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -2376,7 +2492,7 @@ func (x *LostEvent) String() string {
 func (*LostEvent) ProtoMessage() {}
 
 func (x *LostEvent) ProtoReflect() protoreflect.Message {
-	mi := &file_flow_flow_proto_msgTypes[20]
+	mi := &file_flow_flow_proto_msgTypes[19]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -2389,7 +2505,7 @@ func (x *LostEvent) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use LostEvent.ProtoReflect.Descriptor instead.
 func (*LostEvent) Descriptor() ([]byte, []int) {
-	return file_flow_flow_proto_rawDescGZIP(), []int{20}
+	return file_flow_flow_proto_rawDescGZIP(), []int{19}
 }
 
 func (x *LostEvent) GetSource() LostEventSource {
@@ -2421,62 +2537,66 @@ var file_flow_flow_proto_rawDesc = []byte{
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72,
 	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
-	0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x95, 0x07, 0x0a, 0x04, 0x46, 0x6c, 0x6f,
+	0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x07, 0x0a, 0x04, 0x46, 0x6c, 0x6f,
 	0x77, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
 	0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
 	0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d,
 	0x65, 0x12, 0x27, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01,
 	0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x56, 0x65, 0x72, 0x64, 0x69, 0x63,
-	0x74, 0x52, 0x07, 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x72,
-	0x6f, 0x70, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52,
-	0x0a, 0x64, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x08, 0x65,
-	0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
-	0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x52, 0x08, 0x65,
-	0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x02, 0x49, 0x50, 0x18, 0x05, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x50, 0x52, 0x02, 0x49,
-	0x50, 0x12, 0x1c, 0x0a, 0x02, 0x6c, 0x34, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
-	0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x34, 0x52, 0x02, 0x6c, 0x34, 0x12,
-	0x26, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
-	0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
-	0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66,
-	0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0b, 0x64, 0x65,
-	0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x04, 0x54, 0x79, 0x70,
-	0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46,
-	0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a,
-	0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09,
-	0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2b, 0x0a,
-	0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d,
-	0x65, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x02, 0x6c, 0x37,
-	0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x4c, 0x61,
-	0x79, 0x65, 0x72, 0x37, 0x52, 0x02, 0x6c, 0x37, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6c,
-	0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x34,
-	0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x13, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x15, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x69, 0x6c, 0x69, 0x75, 0x6d,
-	0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x54, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73,
-	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x66,
-	0x6c, 0x6f, 0x77, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x0d, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x13, 0x64, 0x65,
-	0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
-	0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x53,
-	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x74, 0x72,
-	0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
-	0x16, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x72, 0x61,
-	0x66, 0x66, 0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x74,
-	0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
-	0x2a, 0x0a, 0x11, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f,
-	0x74, 0x79, 0x70, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x6f, 0x6c, 0x69,
-	0x63, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x53, 0x0a, 0x17, 0x74,
-	0x72, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-	0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x66,
-	0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x15, 0x74, 0x72, 0x61, 0x63, 0x65,
-	0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74,
+	0x74, 0x52, 0x07, 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0b, 0x64, 0x72,
+	0x6f, 0x70, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42,
+	0x02, 0x18, 0x01, 0x52, 0x0a, 0x64, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12,
+	0x2a, 0x0a, 0x08, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65,
+	0x74, 0x52, 0x08, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x02, 0x49,
+	0x50, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49,
+	0x50, 0x52, 0x02, 0x49, 0x50, 0x12, 0x1c, 0x0a, 0x02, 0x6c, 0x34, 0x18, 0x06, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x34, 0x52,
+	0x02, 0x6c, 0x34, 0x12, 0x26, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f,
+	0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x64,
+	0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
+	0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a,
+	0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x66, 0x6c,
+	0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70,
+	0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21,
+	0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0d,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65,
+	0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1c,
+	0x0a, 0x02, 0x6c, 0x37, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x66, 0x6c, 0x6f,
+	0x77, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x37, 0x52, 0x02, 0x6c, 0x37, 0x12, 0x14, 0x0a, 0x05,
+	0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x34, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x43, 0x69,
+	0x6c, 0x69, 0x75, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65,
+	0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x0d, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52,
+	0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e,
+	0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x66, 0x6c,
+	0x6f, 0x77, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x12, 0x64, 0x65, 0x73, 0x74,
+	0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x43,
+	0x0a, 0x11, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x66, 0x6c, 0x6f, 0x77,
+	0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f,
+	0x6e, 0x52, 0x10, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6d, 0x61,
+	0x74, 0x63, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f,
+	0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12,
+	0x53, 0x0a, 0x17, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x1b, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4f, 0x62, 0x73,
+	0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x15, 0x74,
+	0x72, 0x61, 0x63, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
+	0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x10, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x61,
+	0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10,
+	0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+	0x52, 0x0e, 0x64, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63,
 	0x12, 0x1e, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0xa0, 0x8d, 0x06, 0x20,
 	0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
 	0x22, 0xa2, 0x01, 0x0a, 0x06, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x34, 0x12, 0x1d, 0x0a, 0x03, 0x54,
@@ -2616,115 +2736,208 @@ var file_flow_flow_proto_rawDesc = []byte{
 	0x70, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x15, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a,
 	0x68, 0x74, 0x74, 0x70, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74,
 	0x74, 0x70, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x68,
-	0x74, 0x74, 0x70, 0x50, 0x61, 0x74, 0x68, 0x22, 0xb5, 0x01, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c,
-	0x6f, 0x61, 0x64, 0x12, 0x23, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79,
-	0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x43, 0x50, 0x55, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x6f,
-	0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x6c, 0x6f, 0x73, 0x74, 0x12, 0x12,
-	0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
-	0x74, 0x61, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69,
-	0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22,
-	0xce, 0x01, 0x0a, 0x03, 0x44, 0x4e, 0x53, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x10, 0x0a,
-	0x03, 0x69, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, 0x12,
-	0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x74, 0x74,
-	0x6c, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
-	0x09, 0x52, 0x06, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6f, 0x62, 0x73,
-	0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18,
-	0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69,
-	0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x63, 0x6f, 0x64,
-	0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16,
-	0x0a, 0x06, 0x71, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06,
-	0x71, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x72, 0x74, 0x79, 0x70, 0x65,
-	0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73,
-	0x22, 0x34, 0x0a, 0x0a, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12,
-	0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63,
-	0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75,
-	0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a,
-	0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x2a, 0x0a, 0x07, 0x68, 0x65, 0x61,
-	0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x6c, 0x6f,
-	0x77, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65,
-	0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x05, 0x4b, 0x61, 0x66, 0x6b, 0x61, 0x12,
-	0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x05, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f,
-	0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x05, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
-	0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72,
-	0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
-	0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12,
-	0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
-	0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0x3b, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
-	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
-	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
-	0x63, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x09, 0x4c, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74,
-	0x12, 0x2d, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x15, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x4c, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e,
-	0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12,
-	0x26, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6c, 0x6f,
-	0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, 0x75, 0x6d, 0x45, 0x76, 0x65,
-	0x6e, 0x74, 0x73, 0x4c, 0x6f, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75,
-	0x65, 0x52, 0x03, 0x63, 0x70, 0x75, 0x2a, 0x2f, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79,
-	0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59,
-	0x50, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x33, 0x5f, 0x4c, 0x34, 0x10, 0x01, 0x12,
-	0x06, 0x0a, 0x02, 0x4c, 0x37, 0x10, 0x02, 0x2a, 0xea, 0x01, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x63,
-	0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e,
-	0x74, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x50, 0x4f, 0x49,
-	0x4e, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x4f, 0x5f, 0x50, 0x52, 0x4f, 0x58, 0x59,
-	0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x4f, 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x12,
-	0x0c, 0x0a, 0x08, 0x54, 0x4f, 0x5f, 0x53, 0x54, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0e, 0x0a,
-	0x0a, 0x54, 0x4f, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59, 0x10, 0x04, 0x12, 0x0f, 0x0a,
-	0x0b, 0x54, 0x4f, 0x5f, 0x45, 0x4e, 0x44, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x65, 0x12, 0x11,
-	0x0a, 0x0d, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x45, 0x4e, 0x44, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10,
-	0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x10,
-	0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x07,
-	0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x54, 0x41, 0x43, 0x4b, 0x10, 0x08,
-	0x12, 0x10, 0x0a, 0x0c, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59,
-	0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x4e, 0x45, 0x54, 0x57, 0x4f,
-	0x52, 0x4b, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x4f, 0x5f, 0x4e, 0x45, 0x54, 0x57, 0x4f,
-	0x52, 0x4b, 0x10, 0x0b, 0x2a, 0x48, 0x0a, 0x0a, 0x4c, 0x37, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79,
-	0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c, 0x37,
-	0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x51, 0x55, 0x45,
-	0x53, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
-	0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x30,
-	0x0a, 0x09, 0x49, 0x50, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x49,
-	0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04,
-	0x49, 0x50, 0x76, 0x34, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x50, 0x76, 0x36, 0x10, 0x02,
-	0x2a, 0x45, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x56,
-	0x45, 0x52, 0x44, 0x49, 0x43, 0x54, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00,
-	0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x57, 0x41, 0x52, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12,
-	0x0b, 0x0a, 0x07, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05,
-	0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x2a, 0x4a, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x66, 0x66,
-	0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x19, 0x54,
-	0x52, 0x41, 0x46, 0x46, 0x49, 0x43, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e,
-	0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e,
-	0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53,
-	0x53, 0x10, 0x02, 0x2a, 0x39, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
-	0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a,
-	0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x10, 0x09, 0x12, 0x0e,
-	0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x73, 0x74, 0x10, 0x02, 0x2a, 0x67,
-	0x0a, 0x0f, 0x4c, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63,
-	0x65, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c, 0x4f, 0x53,
-	0x54, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x00,
-	0x12, 0x1a, 0x0a, 0x16, 0x50, 0x45, 0x52, 0x46, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52,
-	0x49, 0x4e, 0x47, 0x5f, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15,
-	0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x53, 0x5f,
-	0x51, 0x55, 0x45, 0x55, 0x45, 0x10, 0x02, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
-	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x69, 0x6c, 0x69, 0x75, 0x6d, 0x2f, 0x63, 0x69, 0x6c,
-	0x69, 0x75, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x74, 0x74, 0x70, 0x50, 0x61, 0x74, 0x68, 0x22, 0xce, 0x01, 0x0a, 0x03, 0x44, 0x4e, 0x53, 0x12,
+	0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+	0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6e, 0x61,
+	0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6e, 0x61, 0x6d, 0x65,
+	0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f,
+	0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
+	0x12, 0x14, 0x0a, 0x05, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x05, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x71, 0x74, 0x79, 0x70, 0x65, 0x73,
+	0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x71, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x18,
+	0x0a, 0x07, 0x72, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52,
+	0x07, 0x72, 0x72, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x0a, 0x48, 0x54, 0x54, 0x50,
+	0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8c,
+	0x01, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d,
+	0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74,
+	0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x12, 0x2a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x48, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x9d, 0x01,
+	0x0a, 0x05, 0x4b, 0x61, 0x66, 0x6b, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72,
+	0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x65, 0x72, 0x72,
+	0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x61, 0x70, 0x69,
+	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b,
+	0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79,
+	0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+	0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0x3b, 0x0a,
+	0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09,
+	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x09, 0x4c,
+	0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e,
+	0x4c, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
+	0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x5f, 0x65,
+	0x76, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6c, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0d, 0x6e, 0x75, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x4c, 0x6f, 0x73, 0x74, 0x12,
+	0x2d, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49,
+	0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x63, 0x70, 0x75, 0x2a, 0x2f,
+	0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e,
+	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05,
+	0x4c, 0x33, 0x5f, 0x4c, 0x34, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x4c, 0x37, 0x10, 0x02, 0x2a,
+	0xea, 0x01, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x4b,
+	0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
+	0x54, 0x4f, 0x5f, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x4f,
+	0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x4f, 0x5f, 0x53, 0x54,
+	0x41, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x4f, 0x5f, 0x4f, 0x56, 0x45, 0x52,
+	0x4c, 0x41, 0x59, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x4f, 0x5f, 0x45, 0x4e, 0x44, 0x50,
+	0x4f, 0x49, 0x4e, 0x54, 0x10, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x45,
+	0x4e, 0x44, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x4f,
+	0x4d, 0x5f, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x52, 0x4f,
+	0x4d, 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x07, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x4f, 0x4d,
+	0x5f, 0x53, 0x54, 0x41, 0x43, 0x4b, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x52, 0x4f, 0x4d,
+	0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x52,
+	0x4f, 0x4d, 0x5f, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a,
+	0x54, 0x4f, 0x5f, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x0b, 0x2a, 0x48, 0x0a, 0x0a,
+	0x4c, 0x37, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e,
+	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c, 0x37, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12,
+	0x0b, 0x0a, 0x07, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08,
+	0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x41,
+	0x4d, 0x50, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x30, 0x0a, 0x09, 0x49, 0x50, 0x56, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53,
+	0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x50, 0x76, 0x34, 0x10, 0x01, 0x12, 0x08,
+	0x0a, 0x04, 0x49, 0x50, 0x76, 0x36, 0x10, 0x02, 0x2a, 0x45, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x64,
+	0x69, 0x63, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x56, 0x45, 0x52, 0x44, 0x49, 0x43, 0x54, 0x5f, 0x55,
+	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x57,
+	0x41, 0x52, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x52, 0x4f, 0x50, 0x50,
+	0x45, 0x44, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x2a,
+	0x88, 0x0d, 0x0a, 0x0a, 0x44, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17,
+	0x0a, 0x13, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e,
+	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x12, 0x49, 0x4e, 0x56, 0x41, 0x4c,
+	0x49, 0x44, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x10, 0x82, 0x01,
+	0x12, 0x1c, 0x0a, 0x17, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x44, 0x45, 0x53, 0x54,
+	0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x41, 0x43, 0x10, 0x83, 0x01, 0x12, 0x16,
+	0x0a, 0x11, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45,
+	0x5f, 0x49, 0x50, 0x10, 0x84, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59,
+	0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x85, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x49, 0x4e,
+	0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x44, 0x52, 0x4f,
+	0x50, 0x50, 0x45, 0x44, 0x10, 0x86, 0x01, 0x12, 0x23, 0x0a, 0x1e, 0x43, 0x54, 0x5f, 0x54, 0x52,
+	0x55, 0x4e, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,
+	0x49, 0x44, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x87, 0x01, 0x12, 0x1c, 0x0a, 0x17,
+	0x43, 0x54, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x54, 0x43, 0x50, 0x5f, 0x41,
+	0x43, 0x4b, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x10, 0x88, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x43, 0x54,
+	0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c, 0x34, 0x5f, 0x50, 0x52, 0x4f, 0x54,
+	0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x89, 0x01, 0x12, 0x27, 0x0a, 0x22, 0x43, 0x54, 0x5f, 0x43, 0x41,
+	0x4e, 0x4e, 0x4f, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x4e, 0x54, 0x52,
+	0x59, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x10, 0x8a, 0x01,
+	0x12, 0x1c, 0x0a, 0x17, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f,
+	0x4c, 0x33, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x8b, 0x01, 0x12, 0x15,
+	0x0a, 0x10, 0x4d, 0x49, 0x53, 0x53, 0x45, 0x44, 0x5f, 0x54, 0x41, 0x49, 0x4c, 0x5f, 0x43, 0x41,
+	0x4c, 0x4c, 0x10, 0x8c, 0x01, 0x12, 0x1c, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x57,
+	0x52, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x54, 0x4f, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54,
+	0x10, 0x8d, 0x01, 0x12, 0x18, 0x0a, 0x13, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c,
+	0x34, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x8e, 0x01, 0x12, 0x18, 0x0a,
+	0x13, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x49, 0x43, 0x4d, 0x50, 0x56, 0x34, 0x5f,
+	0x43, 0x4f, 0x44, 0x45, 0x10, 0x8f, 0x01, 0x12, 0x18, 0x0a, 0x13, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
+	0x57, 0x4e, 0x5f, 0x49, 0x43, 0x4d, 0x50, 0x56, 0x34, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x90,
+	0x01, 0x12, 0x18, 0x0a, 0x13, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x49, 0x43, 0x4d,
+	0x50, 0x56, 0x36, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x91, 0x01, 0x12, 0x18, 0x0a, 0x13, 0x55,
+	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x49, 0x43, 0x4d, 0x50, 0x56, 0x36, 0x5f, 0x54, 0x59,
+	0x50, 0x45, 0x10, 0x92, 0x01, 0x12, 0x20, 0x0a, 0x1b, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x52,
+	0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x49, 0x4e, 0x47, 0x5f, 0x54, 0x55, 0x4e, 0x4e, 0x45, 0x4c,
+	0x5f, 0x4b, 0x45, 0x59, 0x10, 0x93, 0x01, 0x12, 0x24, 0x0a, 0x1f, 0x45, 0x52, 0x52, 0x4f, 0x52,
+	0x5f, 0x52, 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x49, 0x4e, 0x47, 0x5f, 0x54, 0x55, 0x4e, 0x4e,
+	0x45, 0x4c, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x94, 0x01, 0x12, 0x1a, 0x0a,
+	0x15, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x56, 0x45, 0x5f,
+	0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x95, 0x01, 0x12, 0x1e, 0x0a, 0x19, 0x55, 0x4e, 0x4b,
+	0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4c, 0x33, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x41,
+	0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x96, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x53, 0x54, 0x41,
+	0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x52, 0x4f, 0x55, 0x54, 0x41, 0x42, 0x4c, 0x45,
+	0x5f, 0x49, 0x50, 0x10, 0x97, 0x01, 0x12, 0x26, 0x0a, 0x21, 0x4e, 0x4f, 0x5f, 0x4d, 0x41, 0x54,
+	0x43, 0x48, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x43, 0x4f, 0x4e, 0x54,
+	0x41, 0x49, 0x4e, 0x45, 0x52, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x98, 0x01, 0x12, 0x27,
+	0x0a, 0x22, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x57, 0x48, 0x49, 0x4c, 0x45, 0x5f, 0x43, 0x4f,
+	0x52, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x33, 0x5f, 0x43, 0x48, 0x45, 0x43,
+	0x4b, 0x53, 0x55, 0x4d, 0x10, 0x99, 0x01, 0x12, 0x27, 0x0a, 0x22, 0x45, 0x52, 0x52, 0x4f, 0x52,
+	0x5f, 0x57, 0x48, 0x49, 0x4c, 0x45, 0x5f, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4e,
+	0x47, 0x5f, 0x4c, 0x34, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x53, 0x55, 0x4d, 0x10, 0x9a, 0x01,
+	0x12, 0x1c, 0x0a, 0x17, 0x43, 0x54, 0x5f, 0x4d, 0x41, 0x50, 0x5f, 0x49, 0x4e, 0x53, 0x45, 0x52,
+	0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x9b, 0x01, 0x12, 0x22,
+	0x0a, 0x1d, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x49, 0x50, 0x56, 0x36, 0x5f, 0x45,
+	0x58, 0x54, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10,
+	0x9c, 0x01, 0x12, 0x23, 0x0a, 0x1e, 0x49, 0x50, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x4d, 0x45, 0x4e,
+	0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x55, 0x50, 0x50, 0x4f,
+	0x52, 0x54, 0x45, 0x44, 0x10, 0x9d, 0x01, 0x12, 0x1e, 0x0a, 0x19, 0x53, 0x45, 0x52, 0x56, 0x49,
+	0x43, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46,
+	0x4f, 0x55, 0x4e, 0x44, 0x10, 0x9e, 0x01, 0x12, 0x28, 0x0a, 0x23, 0x4e, 0x4f, 0x5f, 0x54, 0x55,
+	0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x43, 0x41, 0x50, 0x53, 0x55, 0x4c,
+	0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x44, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0xa0,
+	0x01, 0x12, 0x23, 0x0a, 0x1e, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x4f, 0x5f, 0x49,
+	0x4e, 0x53, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x54, 0x4f, 0x5f, 0x50, 0x52, 0x4f, 0x58, 0x59,
+	0x4d, 0x41, 0x50, 0x10, 0xa1, 0x01, 0x12, 0x2b, 0x0a, 0x26, 0x52, 0x45, 0x41, 0x43, 0x48, 0x45,
+	0x44, 0x5f, 0x45, 0x44, 0x54, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54,
+	0x49, 0x4e, 0x47, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x4f, 0x4e,
+	0x10, 0xa2, 0x01, 0x12, 0x26, 0x0a, 0x21, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43,
+	0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x49,
+	0x4e, 0x47, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0xa3, 0x01, 0x12, 0x1e, 0x0a, 0x19, 0x4c,
+	0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x5f, 0x49, 0x53, 0x5f, 0x55, 0x4e, 0x52,
+	0x45, 0x41, 0x43, 0x48, 0x41, 0x42, 0x4c, 0x45, 0x10, 0xa4, 0x01, 0x12, 0x3a, 0x0a, 0x35, 0x4e,
+	0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
+	0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x54, 0x4f, 0x5f, 0x50, 0x45, 0x52,
+	0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x44, 0x45, 0x43, 0x49,
+	0x53, 0x49, 0x4f, 0x4e, 0x10, 0xa5, 0x01, 0x12, 0x1c, 0x0a, 0x17, 0x55, 0x4e, 0x53, 0x55, 0x50,
+	0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x4c, 0x32, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43,
+	0x4f, 0x4c, 0x10, 0xa6, 0x01, 0x12, 0x22, 0x0a, 0x1d, 0x4e, 0x4f, 0x5f, 0x4d, 0x41, 0x50, 0x50,
+	0x49, 0x4e, 0x47, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x4e, 0x41, 0x54, 0x5f, 0x4d, 0x41, 0x53, 0x51,
+	0x55, 0x45, 0x52, 0x41, 0x44, 0x45, 0x10, 0xa7, 0x01, 0x12, 0x2c, 0x0a, 0x27, 0x55, 0x4e, 0x53,
+	0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f,
+	0x4c, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x4e, 0x41, 0x54, 0x5f, 0x4d, 0x41, 0x53, 0x51, 0x55, 0x45,
+	0x52, 0x41, 0x44, 0x45, 0x10, 0xa8, 0x01, 0x12, 0x16, 0x0a, 0x11, 0x46, 0x49, 0x42, 0x5f, 0x4c,
+	0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0xa9, 0x01, 0x12,
+	0x28, 0x0a, 0x23, 0x45, 0x4e, 0x43, 0x41, 0x50, 0x53, 0x55, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e,
+	0x5f, 0x54, 0x52, 0x41, 0x46, 0x46, 0x49, 0x43, 0x5f, 0x49, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x48,
+	0x49, 0x42, 0x49, 0x54, 0x45, 0x44, 0x10, 0xaa, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x49, 0x4e, 0x56,
+	0x41, 0x4c, 0x49, 0x44, 0x5f, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0xab, 0x01,
+	0x12, 0x13, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x45, 0x4e, 0x44,
+	0x45, 0x52, 0x10, 0xac, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x4e, 0x41, 0x54, 0x5f, 0x4e, 0x4f, 0x54,
+	0x5f, 0x4e, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0xad, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x49, 0x53,
+	0x5f, 0x41, 0x5f, 0x43, 0x4c, 0x55, 0x53, 0x54, 0x45, 0x52, 0x49, 0x50, 0x10, 0xae, 0x01, 0x12,
+	0x2e, 0x0a, 0x29, 0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x4c, 0x4f, 0x47, 0x49, 0x43, 0x41, 0x4c,
+	0x5f, 0x44, 0x41, 0x54, 0x41, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x46, 0x52, 0x41, 0x47, 0x4d, 0x45,
+	0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0xaf, 0x01, 0x12,
+	0x1d, 0x0a, 0x18, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, 0x45, 0x4e, 0x5f, 0x49, 0x43, 0x4d,
+	0x50, 0x56, 0x36, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0xb0, 0x01, 0x12, 0x21,
+	0x0a, 0x1c, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x5f, 0x42, 0x59, 0x5f, 0x4c, 0x42, 0x5f, 0x53,
+	0x52, 0x43, 0x5f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0xb1,
+	0x01, 0x12, 0x19, 0x0a, 0x14, 0x53, 0x4f, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x4f, 0x4b,
+	0x55, 0x50, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0xb2, 0x01, 0x12, 0x19, 0x0a, 0x14,
+	0x53, 0x4f, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x5f, 0x46, 0x41,
+	0x49, 0x4c, 0x45, 0x44, 0x10, 0xb3, 0x01, 0x12, 0x31, 0x0a, 0x2c, 0x50, 0x52, 0x4f, 0x58, 0x59,
+	0x5f, 0x52, 0x45, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x54,
+	0x5f, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x50,
+	0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0xb4, 0x01, 0x2a, 0x4a, 0x0a, 0x10, 0x54, 0x72,
+	0x61, 0x66, 0x66, 0x69, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d,
+	0x0a, 0x19, 0x54, 0x52, 0x41, 0x46, 0x46, 0x49, 0x43, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54,
+	0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a,
+	0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47,
+	0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x2a, 0x39, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
+	0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00,
+	0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x10,
+	0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x73, 0x74, 0x10,
+	0x02, 0x2a, 0x67, 0x0a, 0x0f, 0x4c, 0x6f, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f,
+	0x4c, 0x4f, 0x53, 0x54, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43,
+	0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x45, 0x52, 0x46, 0x5f, 0x45, 0x56, 0x45, 0x4e,
+	0x54, 0x5f, 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x10, 0x01, 0x12,
+	0x19, 0x0a, 0x15, 0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e,
+	0x54, 0x53, 0x5f, 0x51, 0x55, 0x45, 0x55, 0x45, 0x10, 0x02, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69,
+	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x69, 0x6c, 0x69, 0x75, 0x6d, 0x2f,
+	0x63, 0x69, 0x6c, 0x69, 0x75, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x6c,
+	0x6f, 0x77, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2739,32 +2952,32 @@ func file_flow_flow_proto_rawDescGZIP() []byte {
 	return file_flow_flow_proto_rawDescData
 }
 
-var file_flow_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 8)
-var file_flow_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
+var file_flow_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
+var file_flow_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
 var file_flow_flow_proto_goTypes = []interface{}{
 	(FlowType)(0),               // 0: flow.FlowType
 	(TraceObservationPoint)(0),  // 1: flow.TraceObservationPoint
 	(L7FlowType)(0),             // 2: flow.L7FlowType
 	(IPVersion)(0),              // 3: flow.IPVersion
 	(Verdict)(0),                // 4: flow.Verdict
-	(TrafficDirection)(0),       // 5: flow.TrafficDirection
-	(EventType)(0),              // 6: flow.EventType
-	(LostEventSource)(0),        // 7: flow.LostEventSource
-	(*Flow)(nil),                // 8: flow.Flow
-	(*Layer4)(nil),              // 9: flow.Layer4
-	(*Layer7)(nil),              // 10: flow.Layer7
-	(*Endpoint)(nil),            // 11: flow.Endpoint
-	(*TCP)(nil),                 // 12: flow.TCP
-	(*IP)(nil),                  // 13: flow.IP
-	(*Ethernet)(nil),            // 14: flow.Ethernet
-	(*TCPFlags)(nil),            // 15: flow.TCPFlags
-	(*UDP)(nil),                 // 16: flow.UDP
-	(*ICMPv4)(nil),              // 17: flow.ICMPv4
-	(*ICMPv6)(nil),              // 18: flow.ICMPv6
-	(*EventTypeFilter)(nil),     // 19: flow.EventTypeFilter
-	(*CiliumEventType)(nil),     // 20: flow.CiliumEventType
-	(*FlowFilter)(nil),          // 21: flow.FlowFilter
-	(*Payload)(nil),             // 22: flow.Payload
+	(DropReason)(0),             // 5: flow.DropReason
+	(TrafficDirection)(0),       // 6: flow.TrafficDirection
+	(EventType)(0),              // 7: flow.EventType
+	(LostEventSource)(0),        // 8: flow.LostEventSource
+	(*Flow)(nil),                // 9: flow.Flow
+	(*Layer4)(nil),              // 10: flow.Layer4
+	(*Layer7)(nil),              // 11: flow.Layer7
+	(*Endpoint)(nil),            // 12: flow.Endpoint
+	(*TCP)(nil),                 // 13: flow.TCP
+	(*IP)(nil),                  // 14: flow.IP
+	(*Ethernet)(nil),            // 15: flow.Ethernet
+	(*TCPFlags)(nil),            // 16: flow.TCPFlags
+	(*UDP)(nil),                 // 17: flow.UDP
+	(*ICMPv4)(nil),              // 18: flow.ICMPv4
+	(*ICMPv6)(nil),              // 19: flow.ICMPv6
+	(*EventTypeFilter)(nil),     // 20: flow.EventTypeFilter
+	(*CiliumEventType)(nil),     // 21: flow.CiliumEventType
+	(*FlowFilter)(nil),          // 22: flow.FlowFilter
 	(*DNS)(nil),                 // 23: flow.DNS
 	(*HTTPHeader)(nil),          // 24: flow.HTTPHeader
 	(*HTTP)(nil),                // 25: flow.HTTP
@@ -2777,40 +2990,39 @@ var file_flow_flow_proto_goTypes = []interface{}{
 var file_flow_flow_proto_depIdxs = []int32{
 	29, // 0: flow.Flow.time:type_name -> google.protobuf.Timestamp
 	4,  // 1: flow.Flow.verdict:type_name -> flow.Verdict
-	14, // 2: flow.Flow.ethernet:type_name -> flow.Ethernet
-	13, // 3: flow.Flow.IP:type_name -> flow.IP
-	9,  // 4: flow.Flow.l4:type_name -> flow.Layer4
-	11, // 5: flow.Flow.source:type_name -> flow.Endpoint
-	11, // 6: flow.Flow.destination:type_name -> flow.Endpoint
+	15, // 2: flow.Flow.ethernet:type_name -> flow.Ethernet
+	14, // 3: flow.Flow.IP:type_name -> flow.IP
+	10, // 4: flow.Flow.l4:type_name -> flow.Layer4
+	12, // 5: flow.Flow.source:type_name -> flow.Endpoint
+	12, // 6: flow.Flow.destination:type_name -> flow.Endpoint
 	0,  // 7: flow.Flow.Type:type_name -> flow.FlowType
-	10, // 8: flow.Flow.l7:type_name -> flow.Layer7
-	20, // 9: flow.Flow.event_type:type_name -> flow.CiliumEventType
+	11, // 8: flow.Flow.l7:type_name -> flow.Layer7
+	21, // 9: flow.Flow.event_type:type_name -> flow.CiliumEventType
 	27, // 10: flow.Flow.source_service:type_name -> flow.Service
 	27, // 11: flow.Flow.destination_service:type_name -> flow.Service
-	5,  // 12: flow.Flow.traffic_direction:type_name -> flow.TrafficDirection
+	6,  // 12: flow.Flow.traffic_direction:type_name -> flow.TrafficDirection
 	1,  // 13: flow.Flow.trace_observation_point:type_name -> flow.TraceObservationPoint
-	12, // 14: flow.Layer4.TCP:type_name -> flow.TCP
-	16, // 15: flow.Layer4.UDP:type_name -> flow.UDP
-	17, // 16: flow.Layer4.ICMPv4:type_name -> flow.ICMPv4
-	18, // 17: flow.Layer4.ICMPv6:type_name -> flow.ICMPv6
-	2,  // 18: flow.Layer7.type:type_name -> flow.L7FlowType
-	23, // 19: flow.Layer7.dns:type_name -> flow.DNS
-	25, // 20: flow.Layer7.http:type_name -> flow.HTTP
-	26, // 21: flow.Layer7.kafka:type_name -> flow.Kafka
-	15, // 22: flow.TCP.flags:type_name -> flow.TCPFlags
-	3,  // 23: flow.IP.ipVersion:type_name -> flow.IPVersion
-	4,  // 24: flow.FlowFilter.verdict:type_name -> flow.Verdict
-	19, // 25: flow.FlowFilter.event_type:type_name -> flow.EventTypeFilter
-	6,  // 26: flow.Payload.type:type_name -> flow.EventType
-	29, // 27: flow.Payload.time:type_name -> google.protobuf.Timestamp
-	24, // 28: flow.HTTP.headers:type_name -> flow.HTTPHeader
-	7,  // 29: flow.LostEvent.source:type_name -> flow.LostEventSource
-	30, // 30: flow.LostEvent.cpu:type_name -> google.protobuf.Int32Value
-	31, // [31:31] is the sub-list for method output_type
-	31, // [31:31] is the sub-list for method input_type
-	31, // [31:31] is the sub-list for extension type_name
-	31, // [31:31] is the sub-list for extension extendee
-	0,  // [0:31] is the sub-list for field type_name
+	5,  // 14: flow.Flow.drop_reason_desc:type_name -> flow.DropReason
+	13, // 15: flow.Layer4.TCP:type_name -> flow.TCP
+	17, // 16: flow.Layer4.UDP:type_name -> flow.UDP
+	18, // 17: flow.Layer4.ICMPv4:type_name -> flow.ICMPv4
+	19, // 18: flow.Layer4.ICMPv6:type_name -> flow.ICMPv6
+	2,  // 19: flow.Layer7.type:type_name -> flow.L7FlowType
+	23, // 20: flow.Layer7.dns:type_name -> flow.DNS
+	25, // 21: flow.Layer7.http:type_name -> flow.HTTP
+	26, // 22: flow.Layer7.kafka:type_name -> flow.Kafka
+	16, // 23: flow.TCP.flags:type_name -> flow.TCPFlags
+	3,  // 24: flow.IP.ipVersion:type_name -> flow.IPVersion
+	4,  // 25: flow.FlowFilter.verdict:type_name -> flow.Verdict
+	20, // 26: flow.FlowFilter.event_type:type_name -> flow.EventTypeFilter
+	24, // 27: flow.HTTP.headers:type_name -> flow.HTTPHeader
+	8,  // 28: flow.LostEvent.source:type_name -> flow.LostEventSource
+	30, // 29: flow.LostEvent.cpu:type_name -> google.protobuf.Int32Value
+	30, // [30:30] is the sub-list for method output_type
+	30, // [30:30] is the sub-list for method input_type
+	30, // [30:30] is the sub-list for extension type_name
+	30, // [30:30] is the sub-list for extension extendee
+	0,  // [0:30] is the sub-list for field type_name
 }
 
 func init() { file_flow_flow_proto_init() }
@@ -2988,18 +3200,6 @@ func file_flow_flow_proto_init() {
 			}
 		}
 		file_flow_flow_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Payload); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-		file_flow_flow_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*DNS); i {
 			case 0:
 				return &v.state
@@ -3011,7 +3211,7 @@ func file_flow_flow_proto_init() {
 				return nil
 			}
 		}
-		file_flow_flow_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+		file_flow_flow_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*HTTPHeader); i {
 			case 0:
 				return &v.state
@@ -3023,7 +3223,7 @@ func file_flow_flow_proto_init() {
 				return nil
 			}
 		}
-		file_flow_flow_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+		file_flow_flow_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*HTTP); i {
 			case 0:
 				return &v.state
@@ -3035,7 +3235,7 @@ func file_flow_flow_proto_init() {
 				return nil
 			}
 		}
-		file_flow_flow_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+		file_flow_flow_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Kafka); i {
 			case 0:
 				return &v.state
@@ -3047,7 +3247,7 @@ func file_flow_flow_proto_init() {
 				return nil
 			}
 		}
-		file_flow_flow_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+		file_flow_flow_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Service); i {
 			case 0:
 				return &v.state
@@ -3059,7 +3259,7 @@ func file_flow_flow_proto_init() {
 				return nil
 			}
 		}
-		file_flow_flow_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+		file_flow_flow_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*LostEvent); i {
 			case 0:
 				return &v.state
@@ -3088,8 +3288,8 @@ func file_flow_flow_proto_init() {
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_flow_flow_proto_rawDesc,
-			NumEnums:      8,
-			NumMessages:   21,
+			NumEnums:      9,
+			NumMessages:   20,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/api/v1/flow/flow.pb.json.go b/api/v1/flow/flow.pb.json.go
index 240cdc4490..899651301f 100644
--- a/api/v1/flow/flow.pb.json.go
+++ b/api/v1/flow/flow.pb.json.go
@@ -261,24 +261,6 @@ func (msg *FlowFilter) UnmarshalJSON(b []byte) error {
 	}).Unmarshal(bytes.NewReader(b), msg)
 }
 
-// MarshalJSON implements json.Marshaler
-func (msg *Payload) MarshalJSON() ([]byte, error) {
-	var buf bytes.Buffer
-	err := (&jsonpb.Marshaler{
-		EnumsAsInts:  false,
-		EmitDefaults: false,
-		OrigName:     true,
-	}).Marshal(&buf, msg)
-	return buf.Bytes(), err
-}
-
-// UnmarshalJSON implements json.Unmarshaler
-func (msg *Payload) UnmarshalJSON(b []byte) error {
-	return (&jsonpb.Unmarshaler{
-		AllowUnknownFields: false,
-	}).Unmarshal(bytes.NewReader(b), msg)
-}
-
 // MarshalJSON implements json.Marshaler
 func (msg *DNS) MarshalJSON() ([]byte, error) {
 	var buf bytes.Buffer
diff --git a/api/v1/flow/flow.proto b/api/v1/flow/flow.proto
index 3cc15a095b..6f4810082a 100644
--- a/api/v1/flow/flow.proto
+++ b/api/v1/flow/flow.proto
@@ -26,7 +26,8 @@ message Flow {
     Verdict verdict = 2;
 
     // only applicable to Verdict = DROPPED.
-    uint32 drop_reason = 3;
+    // deprecated in favor of drop_reason_desc.
+    uint32 drop_reason = 3 [deprecated=true];
 
     // l2
     Ethernet ethernet = 4;
@@ -77,6 +78,9 @@ message Flow {
     // Only applicable to cilium trace notifications, blank for other types.
     TraceObservationPoint trace_observation_point = 24;
 
+    // only applicable to Verdict = DROPPED.
+    DropReason drop_reason_desc = 25;
+
     // This is a temporary workaround to support summary field for pb.Flow without
     // duplicating logic from the old parser. This field will be removed once we
     // fully migrate to the new parser.
@@ -214,6 +218,64 @@ enum Verdict {
     ERROR = 3;
 }
 
+// Taken from pkg/monitor/api/drop.go. Note that non-drop reasons (i.e. values
+// less than api.DropMin) are not used here.
+enum DropReason {
+    // non-drop reasons
+    DROP_REASON_UNKNOWN = 0;
+    // drop reasons
+    INVALID_SOURCE_MAC = 130;
+    INVALID_DESTINATION_MAC = 131;
+    INVALID_SOURCE_IP = 132;
+    POLICY_DENIED = 133;
+    INVALID_PACKET_DROPPED = 134;
+    CT_TRUNCATED_OR_INVALID_HEADER = 135;
+    CT_MISSING_TCP_ACK_FLAG = 136;
+    CT_UNKNOWN_L4_PROTOCOL = 137;
+    CT_CANNOT_CREATE_ENTRY_FROM_PACKET = 138;
+    UNSUPPORTED_L3_PROTOCOL = 139;
+    MISSED_TAIL_CALL = 140;
+    ERROR_WRITING_TO_PACKET = 141;
+    UNKNOWN_L4_PROTOCOL = 142;
+    UNKNOWN_ICMPV4_CODE = 143;
+    UNKNOWN_ICMPV4_TYPE = 144;
+    UNKNOWN_ICMPV6_CODE = 145;
+    UNKNOWN_ICMPV6_TYPE = 146;
+    ERROR_RETRIEVING_TUNNEL_KEY = 147;
+    ERROR_RETRIEVING_TUNNEL_OPTIONS = 148;
+    INVALID_GENEVE_OPTION = 149;
+    UNKNOWN_L3_TARGET_ADDRESS = 150;
+    STALE_OR_UNROUTABLE_IP = 151;
+    NO_MATCHING_LOCAL_CONTAINER_FOUND = 152;
+    ERROR_WHILE_CORRECTING_L3_CHECKSUM = 153;
+    ERROR_WHILE_CORRECTING_L4_CHECKSUM = 154;
+    CT_MAP_INSERTION_FAILED = 155;
+    INVALID_IPV6_EXTENSION_HEADER = 156;
+    IP_FRAGMENTATION_NOT_SUPPORTED = 157;
+    SERVICE_BACKEND_NOT_FOUND = 158;
+    NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT = 160;
+    FAILED_TO_INSERT_INTO_PROXYMAP = 161;
+    REACHED_EDT_RATE_LIMITING_DROP_HORIZON = 162;
+    UNKNOWN_CONNECTION_TRACKING_STATE = 163;
+    LOCAL_HOST_IS_UNREACHABLE = 164;
+    NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION = 165;
+    UNSUPPORTED_L2_PROTOCOL = 166;
+    NO_MAPPING_FOR_NAT_MASQUERADE = 167;
+    UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE = 168;
+    FIB_LOOKUP_FAILED = 169;
+    ENCAPSULATION_TRAFFIC_IS_PROHIBITED = 170;
+    INVALID_IDENTITY = 171;
+    UNKNOWN_SENDER = 172;
+    NAT_NOT_NEEDED = 173;
+    IS_A_CLUSTERIP = 174;
+    FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND = 175;
+    FORBIDDEN_ICMPV6_MESSAGE = 176;
+    DENIED_BY_LB_SRC_RANGE_CHECK = 177;
+    SOCKET_LOOKUP_FAILED = 178;
+    SOCKET_ASSIGN_FAILED = 179;
+    PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL = 180;
+}
+
 enum TrafficDirection {
     TRAFFIC_DIRECTION_UNKNOWN = 0;
     INGRESS = 1;
@@ -316,22 +378,6 @@ enum EventType {
     RecordLost = 2;
 }
 
-// Payload is the payload, i.e. the data the monitor returns.
-message Payload {
-    // type is the event type perf returns.
-    EventType type = 1;
-    // CPU is the CPU id for this event.
-    int32 CPU = 2;
-    // lost is the number of events lost for a given CPU.
-    uint64 lost = 3;
-    // data is the sample data returned by perf.
-    bytes data = 4;
-    // time when the event was observed
-    google.protobuf.Timestamp time = 5;
-    // the host name from which the payload was captured.
-    string host_name = 6;
-}
-
 // DNS flow. This is basically directly mapped from Cilium's LogRecordDNS:
 //     https://github.com/cilium/cilium/blob/04f3889d627774f79e56d14ddbc165b3169e2d01/pkg/proxy/accesslog/record.go#L264
 message DNS {
diff --git a/api/v1/models/backend_address.go b/api/v1/models/backend_address.go
index 4675a9767f..d305c02d8b 100644
--- a/api/v1/models/backend_address.go
+++ b/api/v1/models/backend_address.go
@@ -29,6 +29,9 @@ type BackendAddress struct {
 
 	// Layer 4 port number
 	Port uint16 `json:"port,omitempty"`
+
+	// Layer 4 protocol (TCP, UDP, etc)
+	Protocol string `json:"protocol,omitempty"`
 }
 
 // Validate validates this backend address
diff --git a/api/v1/observer/observer.pb.go b/api/v1/observer/observer.pb.go
index 3208bc875f..193a6771f4 100644
--- a/api/v1/observer/observer.pb.go
+++ b/api/v1/observer/observer.pb.go
@@ -102,6 +102,63 @@ const Verdict_ERROR = flow.Verdict_ERROR
 var Verdict_name = flow.Verdict_name
 var Verdict_value = flow.Verdict_value
 
+type DropReason = flow.DropReason
+
+const DropReason_DROP_REASON_UNKNOWN = flow.DropReason_DROP_REASON_UNKNOWN
+const DropReason_INVALID_SOURCE_MAC = flow.DropReason_INVALID_SOURCE_MAC
+const DropReason_INVALID_DESTINATION_MAC = flow.DropReason_INVALID_DESTINATION_MAC
+const DropReason_INVALID_SOURCE_IP = flow.DropReason_INVALID_SOURCE_IP
+const DropReason_POLICY_DENIED = flow.DropReason_POLICY_DENIED
+const DropReason_INVALID_PACKET_DROPPED = flow.DropReason_INVALID_PACKET_DROPPED
+const DropReason_CT_TRUNCATED_OR_INVALID_HEADER = flow.DropReason_CT_TRUNCATED_OR_INVALID_HEADER
+const DropReason_CT_MISSING_TCP_ACK_FLAG = flow.DropReason_CT_MISSING_TCP_ACK_FLAG
+const DropReason_CT_UNKNOWN_L4_PROTOCOL = flow.DropReason_CT_UNKNOWN_L4_PROTOCOL
+const DropReason_CT_CANNOT_CREATE_ENTRY_FROM_PACKET = flow.DropReason_CT_CANNOT_CREATE_ENTRY_FROM_PACKET
+const DropReason_UNSUPPORTED_L3_PROTOCOL = flow.DropReason_UNSUPPORTED_L3_PROTOCOL
+const DropReason_MISSED_TAIL_CALL = flow.DropReason_MISSED_TAIL_CALL
+const DropReason_ERROR_WRITING_TO_PACKET = flow.DropReason_ERROR_WRITING_TO_PACKET
+const DropReason_UNKNOWN_L4_PROTOCOL = flow.DropReason_UNKNOWN_L4_PROTOCOL
+const DropReason_UNKNOWN_ICMPV4_CODE = flow.DropReason_UNKNOWN_ICMPV4_CODE
+const DropReason_UNKNOWN_ICMPV4_TYPE = flow.DropReason_UNKNOWN_ICMPV4_TYPE
+const DropReason_UNKNOWN_ICMPV6_CODE = flow.DropReason_UNKNOWN_ICMPV6_CODE
+const DropReason_UNKNOWN_ICMPV6_TYPE = flow.DropReason_UNKNOWN_ICMPV6_TYPE
+const DropReason_ERROR_RETRIEVING_TUNNEL_KEY = flow.DropReason_ERROR_RETRIEVING_TUNNEL_KEY
+const DropReason_ERROR_RETRIEVING_TUNNEL_OPTIONS = flow.DropReason_ERROR_RETRIEVING_TUNNEL_OPTIONS
+const DropReason_INVALID_GENEVE_OPTION = flow.DropReason_INVALID_GENEVE_OPTION
+const DropReason_UNKNOWN_L3_TARGET_ADDRESS = flow.DropReason_UNKNOWN_L3_TARGET_ADDRESS
+const DropReason_STALE_OR_UNROUTABLE_IP = flow.DropReason_STALE_OR_UNROUTABLE_IP
+const DropReason_NO_MATCHING_LOCAL_CONTAINER_FOUND = flow.DropReason_NO_MATCHING_LOCAL_CONTAINER_FOUND
+const DropReason_ERROR_WHILE_CORRECTING_L3_CHECKSUM = flow.DropReason_ERROR_WHILE_CORRECTING_L3_CHECKSUM
+const DropReason_ERROR_WHILE_CORRECTING_L4_CHECKSUM = flow.DropReason_ERROR_WHILE_CORRECTING_L4_CHECKSUM
+const DropReason_CT_MAP_INSERTION_FAILED = flow.DropReason_CT_MAP_INSERTION_FAILED
+const DropReason_INVALID_IPV6_EXTENSION_HEADER = flow.DropReason_INVALID_IPV6_EXTENSION_HEADER
+const DropReason_IP_FRAGMENTATION_NOT_SUPPORTED = flow.DropReason_IP_FRAGMENTATION_NOT_SUPPORTED
+const DropReason_SERVICE_BACKEND_NOT_FOUND = flow.DropReason_SERVICE_BACKEND_NOT_FOUND
+const DropReason_NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT = flow.DropReason_NO_TUNNEL_OR_ENCAPSULATION_ENDPOINT
+const DropReason_FAILED_TO_INSERT_INTO_PROXYMAP = flow.DropReason_FAILED_TO_INSERT_INTO_PROXYMAP
+const DropReason_REACHED_EDT_RATE_LIMITING_DROP_HORIZON = flow.DropReason_REACHED_EDT_RATE_LIMITING_DROP_HORIZON
+const DropReason_UNKNOWN_CONNECTION_TRACKING_STATE = flow.DropReason_UNKNOWN_CONNECTION_TRACKING_STATE
+const DropReason_LOCAL_HOST_IS_UNREACHABLE = flow.DropReason_LOCAL_HOST_IS_UNREACHABLE
+const DropReason_NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION = flow.DropReason_NO_CONFIGURATION_AVAILABLE_TO_PERFORM_POLICY_DECISION
+const DropReason_UNSUPPORTED_L2_PROTOCOL = flow.DropReason_UNSUPPORTED_L2_PROTOCOL
+const DropReason_NO_MAPPING_FOR_NAT_MASQUERADE = flow.DropReason_NO_MAPPING_FOR_NAT_MASQUERADE
+const DropReason_UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE = flow.DropReason_UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE
+const DropReason_FIB_LOOKUP_FAILED = flow.DropReason_FIB_LOOKUP_FAILED
+const DropReason_ENCAPSULATION_TRAFFIC_IS_PROHIBITED = flow.DropReason_ENCAPSULATION_TRAFFIC_IS_PROHIBITED
+const DropReason_INVALID_IDENTITY = flow.DropReason_INVALID_IDENTITY
+const DropReason_UNKNOWN_SENDER = flow.DropReason_UNKNOWN_SENDER
+const DropReason_NAT_NOT_NEEDED = flow.DropReason_NAT_NOT_NEEDED
+const DropReason_IS_A_CLUSTERIP = flow.DropReason_IS_A_CLUSTERIP
+const DropReason_FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND = flow.DropReason_FIRST_LOGICAL_DATAGRAM_FRAGMENT_NOT_FOUND
+const DropReason_FORBIDDEN_ICMPV6_MESSAGE = flow.DropReason_FORBIDDEN_ICMPV6_MESSAGE
+const DropReason_DENIED_BY_LB_SRC_RANGE_CHECK = flow.DropReason_DENIED_BY_LB_SRC_RANGE_CHECK
+const DropReason_SOCKET_LOOKUP_FAILED = flow.DropReason_SOCKET_LOOKUP_FAILED
+const DropReason_SOCKET_ASSIGN_FAILED = flow.DropReason_SOCKET_ASSIGN_FAILED
+const DropReason_PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL = flow.DropReason_PROXY_REDIRECTION_NOT_SUPPORTED_FOR_PROTOCOL
+
+var DropReason_name = flow.DropReason_name
+var DropReason_value = flow.DropReason_value
+
 type TrafficDirection = flow.TrafficDirection
 
 const TrafficDirection_TRAFFIC_DIRECTION_UNKNOWN = flow.TrafficDirection_TRAFFIC_DIRECTION_UNKNOWN
@@ -150,7 +207,6 @@ type ICMPv6 = flow.ICMPv6
 type EventTypeFilter = flow.EventTypeFilter
 type CiliumEventType = flow.CiliumEventType
 type FlowFilter = flow.FlowFilter
-type Payload = flow.Payload
 type DNS = flow.DNS
 type HTTPHeader = flow.HTTPHeader
 type HTTP = flow.HTTP
diff --git a/api/v1/observer/observer.proto b/api/v1/observer/observer.proto
index 5b0905988b..dfce1b9b77 100644
--- a/api/v1/observer/observer.proto
+++ b/api/v1/observer/observer.proto
@@ -23,8 +23,8 @@ package observer;
 
 option go_package = "github.com/cilium/cilium/api/v1/observer";
 
-// Observer returns a stream of Payload depending on which filter the user
-// want to observer.
+// Observer returns a stream of Flows depending on which filter the user want
+// to observe.
 service Observer {
     // GetFlows returning structured data, meant to eventually obsolete GetLastNFlows.
     rpc GetFlows(GetFlowsRequest) returns (stream GetFlowsResponse) {}
diff --git a/api/v1/openapi.yaml b/api/v1/openapi.yaml
index f9c552725d..c045df68b8 100644
--- a/api/v1/openapi.yaml
+++ b/api/v1/openapi.yaml
@@ -2250,6 +2250,9 @@ definitions:
         description: Layer 4 port number
         type: integer
         format: uint16
+      protocol:
+        description: Layer 4 protocol (TCP, UDP, etc)
+        type: string
       nodeName:
         description: Optional name of the node on which this backend runs
         type: string
diff --git a/api/v1/server/embedded_spec.go b/api/v1/server/embedded_spec.go
index 375d4011fb..1d8b94e1a1 100644
--- a/api/v1/server/embedded_spec.go
+++ b/api/v1/server/embedded_spec.go
@@ -1429,6 +1429,10 @@ func init() {
           "description": "Layer 4 port number",
           "type": "integer",
           "format": "uint16"
+        },
+        "protocol": {
+          "description": "Layer 4 protocol (TCP, UDP, etc)",
+          "type": "string"
         }
       }
     },
@@ -5147,6 +5151,10 @@ func init() {
           "description": "Layer 4 port number",
           "type": "integer",
           "format": "uint16"
+        },
+        "protocol": {
+          "description": "Layer 4 protocol (TCP, UDP, etc)",
+          "type": "string"
         }
       }
     },
diff --git a/bpf/bpf_sock.c b/bpf/bpf_sock.c
index afa690534a..2a746c53f3 100644
--- a/bpf/bpf_sock.c
+++ b/bpf/bpf_sock.c
@@ -272,15 +272,17 @@ static __always_inline int __sock4_xlate_fwd(struct bpf_sock_addr *ctx,
 	const bool in_hostns = ctx_in_hostns(ctx_full, &id.client_cookie);
 	struct lb4_backend *backend;
 	struct lb4_service *svc;
+	__u32 proto = ctx->protocol;
 	struct lb4_key key = {
 		.address	= ctx->user_ip4,
 		.dport		= ctx_dst_port(ctx),
+		.proto		= proto,
 	}, orig_key = key;
 	struct lb4_service *backend_slot;
 	bool backend_from_affinity = false;
 	__u32 backend_id = 0;
 
-	if (!udp_only && !sock_proto_enabled(ctx->protocol))
+	if (!udp_only && !sock_proto_enabled(proto))
 		return -ENOTSUP;
 
 	/* In case a direct match fails, we try to look-up surrogate
@@ -372,12 +374,14 @@ static __always_inline int __sock4_bind(struct bpf_sock *ctx,
 					struct bpf_sock *ctx_full)
 {
 	struct lb4_service *svc;
+	__u32 proto = ctx->protocol;
 	struct lb4_key key = {
 		.address	= ctx->src_ip4,
 		.dport		= ctx_src_port(ctx),
+		.proto		= proto,
 	};
 
-	if (!sock_proto_enabled(ctx->protocol) ||
+	if (!sock_proto_enabled(proto) ||
 	    !ctx_in_hostns(ctx_full, NULL))
 		return 0;
 
@@ -428,6 +432,7 @@ static __always_inline int __sock4_xlate_rev(struct bpf_sock_addr *ctx,
 		struct lb4_key svc_key = {
 			.address	= val->address,
 			.dport		= val->port,
+			.proto		= ctx->protocol,
 		};
 
 		svc = lb4_lookup_service(&svc_key, true);
@@ -672,11 +677,13 @@ sock6_bind_v4_in_v6(struct bpf_sock *ctx __maybe_unused)
 static __always_inline int __sock6_bind(struct bpf_sock *ctx)
 {
 	struct lb6_service *svc;
+	__u32 proto = ctx->protocol;
 	struct lb6_key key = {
 		.dport		= ctx_src_port(ctx),
+		.proto		= proto,
 	};
 
-	if (!sock_proto_enabled(ctx->protocol) ||
+	if (!sock_proto_enabled(proto) ||
 	    !ctx_in_hostns(ctx, NULL))
 		return 0;
 
@@ -715,14 +722,16 @@ static __always_inline int __sock6_xlate_fwd(struct bpf_sock_addr *ctx,
 	const bool in_hostns = ctx_in_hostns(ctx, &id.client_cookie);
 	struct lb6_backend *backend;
 	struct lb6_service *svc;
+	__u32 proto = ctx->protocol;
 	struct lb6_key key = {
 		.dport		= ctx_dst_port(ctx),
+		.proto		= proto,
 	}, orig_key;
 	struct lb6_service *backend_slot;
 	bool backend_from_affinity = false;
 	__u32 backend_id = 0;
 
-	if (!udp_only && !sock_proto_enabled(ctx->protocol))
+	if (!udp_only && !sock_proto_enabled(proto))
 		return -ENOTSUP;
 
 	ctx_get_v6_address(ctx, &key.address);
@@ -839,6 +848,7 @@ static __always_inline int __sock6_xlate_rev(struct bpf_sock_addr *ctx)
 		struct lb6_key svc_key = {
 			.address	= val->address,
 			.dport		= val->port,
+			.proto		= ctx->protocol,
 		};
 
 		svc = lb6_lookup_service(&svc_key, true);
diff --git a/bpf/init.sh b/bpf/init.sh
index 5761abc969..2db6eb611c 100755
--- a/bpf/init.sh
+++ b/bpf/init.sh
@@ -511,8 +511,7 @@ if [ "$MODE" = "vxlan" -o "$MODE" = "geneve" ]; then
 	}
 	ip link set $ENCAP_DEV mtu $MTU || encap_fail
 
-	setup_dev $ENCAP_DEV
-	ip link set $ENCAP_DEV up || encap_fail
+	setup_dev $ENCAP_DEV || encap_fail
 
 	ENCAP_IDX=$(cat /sys/class/net/${ENCAP_DEV}/ifindex)
 	sed -i '/^#.*ENCAP_IFINDEX.*$/d' $RUNDIR/globals/node_config.h
diff --git a/bpf/lib/common.h b/bpf/lib/common.h
index ae2edcae89..60a430ed4b 100644
--- a/bpf/lib/common.h
+++ b/bpf/lib/common.h
@@ -632,7 +632,7 @@ struct lb6_key {
 	union v6addr address;	/* Service virtual IPv6 address */
 	__be16 dport;		/* L4 port filter, if unset, all ports apply */
 	__u16 backend_slot;	/* Backend iterator, 0 indicates the svc frontend */
-	__u8 proto;		/* L4 protocol, currently not used (set to 0) */
+	__u8 proto;		/* L4 protocol */
 	__u8 scope;		/* LB_LOOKUP_SCOPE_* for externalTrafficPolicy=Local */
 	__u8 pad[2];
 };
@@ -680,7 +680,7 @@ struct lb4_key {
 	__be32 address;		/* Service virtual IPv4 address */
 	__be16 dport;		/* L4 port filter, if unset, all ports apply */
 	__u16 backend_slot;	/* Backend iterator, 0 indicates the svc frontend */
-	__u8 proto;		/* L4 protocol, currently not used (set to 0) */
+	__u8 proto;		/* L4 protocol */
 	__u8 scope;		/* LB_LOOKUP_SCOPE_* for externalTrafficPolicy=Local */
 	__u8 pad[2];
 };
diff --git a/bpf/lib/lb.h b/bpf/lib/lb.h
index 7b0d0db61b..dd499105cd 100644
--- a/bpf/lib/lb.h
+++ b/bpf/lib/lb.h
@@ -500,8 +500,7 @@ static __always_inline int lb6_extract_key(struct __ctx_buff *ctx __maybe_unused
 					   int dir)
 {
 	union v6addr *addr;
-	/* FIXME(brb): set after adding support for different L4 protocols in LB */
-	key->proto = 0;
+	key->proto = tuple->nexthdr;
 	addr = (dir == CT_INGRESS) ? &tuple->saddr : &tuple->daddr;
 	ipv6_addr_copy(&key->address, addr);
 	csum_l4_offset_and_flags(tuple->nexthdr, csum_off);
@@ -1020,8 +1019,7 @@ static __always_inline int lb4_extract_key(struct __ctx_buff *ctx __maybe_unused
 					   struct csum_offset *csum_off,
 					   int dir)
 {
-	/* FIXME: set after adding support for different L4 protocols in LB */
-	key->proto = 0;
+	key->proto = ip4->protocol;
 	key->address = (dir == CT_INGRESS) ? ip4->saddr : ip4->daddr;
 	csum_l4_offset_and_flags(ip4->protocol, csum_off);
 
diff --git a/bpf/sockops/bpf_redir.c b/bpf/sockops/bpf_redir.c
index 77855a71ae..f55fdab14a 100644
--- a/bpf/sockops/bpf_redir.c
+++ b/bpf/sockops/bpf_redir.c
@@ -28,6 +28,10 @@ static __always_inline void sk_msg_extract4_key(const struct sk_msg_md *msg,
 	key->dip4 = msg->remote_ip4;
 	key->sip4 = msg->local_ip4;
 	key->family = ENDPOINT_KEY_IPV4;
+	/* Only TCP packets flow through sk_msg progs.
+	 * cf GH issue #13490 to fix
+	 */
+	key->protocol = IPPROTO_TCP;
 
 	key->sport = (bpf_ntohl(msg->local_port) >> 16);
 	/* clang-7.1 or higher seems to think it can do a 16-bit read here
diff --git a/bpf/sockops/bpf_sockops.c b/bpf/sockops/bpf_sockops.c
index a932a3194b..13545c4e80 100644
--- a/bpf/sockops/bpf_sockops.c
+++ b/bpf/sockops/bpf_sockops.c
@@ -29,6 +29,11 @@ static __always_inline void sk_extract4_key(const struct bpf_sock_ops *ops,
 	key->dip4 = ops->remote_ip4;
 	key->sip4 = ops->local_ip4;
 	key->family = ENDPOINT_KEY_IPV4;
+	/* We will get misses on UDP, but the verifier
+	 * does not allow access to the socket field until >= 5.3
+	 * cf GH issue #13490 to fix
+	 */
+	key->protocol = IPPROTO_TCP;
 
 	key->sport = (bpf_ntohl(ops->local_port) >> 16);
 	/* clang-7.1 or higher seems to think it can do a 16-bit read here
@@ -45,6 +50,7 @@ static __always_inline void sk_lb4_key(struct lb4_key *lb4,
 	/* SK MSG is always egress, so use daddr */
 	lb4->address = key->dip4;
 	lb4->dport = key->dport;
+	lb4->proto = key->protocol;
 }
 
 static __always_inline bool redirect_to_proxy(int verdict)
diff --git a/bpf/sockops/bpf_sockops.h b/bpf/sockops/bpf_sockops.h
index 13c4a44025..f45ad0ffe0 100644
--- a/bpf/sockops/bpf_sockops.h
+++ b/bpf/sockops/bpf_sockops.h
@@ -24,7 +24,7 @@ struct sock_key {
 		union v6addr	dip6;
 	};
 	__u8 family;
-	__u8 pad7;
+	__u8 protocol;
 	__u16 pad8;
 	__u32 sport;
 	__u32 dport;
diff --git a/cilium/cmd/service_update.go b/cilium/cmd/service_update.go
index bf9eb225bd..76fe88285c 100644
--- a/cilium/cmd/service_update.go
+++ b/cilium/cmd/service_update.go
@@ -37,6 +37,7 @@ var (
 	localRedirect      bool
 	idU                uint64
 	frontend           string
+	protocol           string
 	backends           []string
 )
 
@@ -60,11 +61,36 @@ func init() {
 	serviceUpdateCmd.Flags().StringVarP(&k8sTrafficPolicy, "k8s-traffic-policy", "", "Cluster", "Set service with k8s externalTrafficPolicy as {Local,Cluster}")
 	serviceUpdateCmd.Flags().BoolVarP(&k8sClusterInternal, "k8s-cluster-internal", "", false, "Set service as cluster-internal for externalTrafficPolicy=Local")
 	serviceUpdateCmd.Flags().StringVarP(&frontend, "frontend", "", "", "Frontend address")
+	serviceUpdateCmd.Flags().StringVarP(&protocol, "protocol", "", "tcp", "Protocol for service (e.g. TCP, UDP)")
 	serviceUpdateCmd.Flags().StringSliceVarP(&backends, "backends", "", []string{}, "Backend address or addresses (<IP:Port>)")
 }
 
-func parseFrontendAddress(address string) (*models.FrontendAddress, net.IP) {
-	frontend, err := net.ResolveTCPAddr("tcp", address)
+func parseAddress(l4Protocol, address string) (ip net.IP, port int, proto string, err error) {
+	switch proto = strings.ToLower(l4Protocol); proto {
+	case "tcp":
+		var tcpAddr *net.TCPAddr
+		tcpAddr, err = net.ResolveTCPAddr(proto, address)
+		if err != nil {
+			return
+		}
+		ip = tcpAddr.IP
+		port = tcpAddr.Port
+	case "udp":
+		var udpAddr *net.UDPAddr
+		udpAddr, err = net.ResolveUDPAddr(proto, address)
+		if err != nil {
+			return
+		}
+		ip = udpAddr.IP
+		port = udpAddr.Port
+	default:
+		err = fmt.Errorf("unrecognized protocol %q", l4Protocol)
+	}
+	return
+}
+
+func parseFrontendAddress(l4Protocol, address string) (*models.FrontendAddress, net.IP) {
+	ip, port, proto, err := parseAddress(l4Protocol, address)
 	if err != nil {
 		Fatalf("Unable to parse frontend address: %s\n", err)
 	}
@@ -74,13 +100,12 @@ func parseFrontendAddress(address string) (*models.FrontendAddress, net.IP) {
 		scope = models.FrontendAddressScopeInternal
 	}
 
-	// FIXME support more than TCP
 	return &models.FrontendAddress{
-		IP:       frontend.IP.String(),
-		Port:     uint16(frontend.Port),
-		Protocol: models.FrontendAddressProtocolTCP,
+		IP:       ip.String(),
+		Port:     uint16(port),
+		Protocol: proto,
 		Scope:    scope,
-	}, frontend.IP
+	}, ip
 }
 
 func boolToInt(set bool) int {
@@ -92,7 +117,7 @@ func boolToInt(set bool) int {
 
 func updateService(cmd *cobra.Command, args []string) {
 	id := int64(idU)
-	fa, faIP := parseFrontendAddress(frontend)
+	fa, faIP := parseFrontendAddress(protocol, frontend)
 
 	var spec *models.ServiceSpec
 	svc, err := client.GetServiceID(id)
@@ -150,20 +175,19 @@ func updateService(cmd *cobra.Command, args []string) {
 
 	spec.BackendAddresses = nil
 	for _, backend := range backends {
-		beAddr, err := net.ResolveTCPAddr("tcp", backend)
+		ip, port, proto, err := parseAddress(protocol, backend)
 		if err != nil {
-			Fatalf("Cannot parse backend address \"%s\": %s", backend, err)
+			Fatalf("Cannot parse backend address %q: %s", backend, err)
 		}
-
 		// Backend ID will be set by the daemon
-		be := loadbalancer.NewBackend(0, loadbalancer.TCP, beAddr.IP, uint16(beAddr.Port))
+		be := loadbalancer.NewBackend(0, loadbalancer.L4Type(strings.ToUpper(proto)), ip, uint16(port))
 
 		if be.IsIPv6() && faIP.To4() != nil {
 			Fatalf("Address mismatch between frontend and backend %s", backend)
 		}
 
-		if fa.Port == 0 && beAddr.Port != 0 {
-			Fatalf("L4 backend found (%v) with L3 frontend", beAddr)
+		if fa.Port == 0 && port != 0 {
+			Fatalf("L4 backend found (%s:%d) with L3 frontend", ip, port)
 		}
 
 		ba := be.GetBackendModel()
diff --git a/daemon/cmd/api_limits.go b/daemon/cmd/api_limits.go
index 0336b0678d..c127af80eb 100644
--- a/daemon/cmd/api_limits.go
+++ b/daemon/cmd/api_limits.go
@@ -119,6 +119,11 @@ func (a *apiRateLimitingMetrics) ProcessedRequest(name string, v rate.MetricsVal
 	metrics.APILimiterRateLimit.WithLabelValues(name, "limit").Set(float64(v.Limit))
 	metrics.APILimiterRateLimit.WithLabelValues(name, "burst").Set(float64(v.Burst))
 	metrics.APILimiterAdjustmentFactor.WithLabelValues(name).Set(v.AdjustmentFactor)
-	metrics.APILimiterWaitHistoryDuration.WithLabelValues(name).Observe(v.WaitDuration.Seconds())
-	metrics.APILimiterProcessedRequests.WithLabelValues(name, metrics.Error2Outcome(v.Error)).Inc()
+
+	if v.Outcome == "" {
+		metrics.APILimiterWaitHistoryDuration.WithLabelValues(name).Observe(v.WaitDuration.Seconds())
+		v.Outcome = metrics.Error2Outcome(v.Error)
+	}
+
+	metrics.APILimiterProcessedRequests.WithLabelValues(name, v.Outcome).Inc()
 }
diff --git a/go.mod b/go.mod
index 1b5e0d65fe..59e4b39f49 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
 	github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
 	github.com/aws/aws-sdk-go-v2 v0.24.0
 	github.com/blang/semver v3.5.0+incompatible
-	github.com/cilium/arping v1.0.1-0.20190728065459-c5eaf8d7a710
+	github.com/cilium/arping v1.0.1-0.20201009104213-b546132ab753
 	github.com/cilium/deepequal-gen v0.0.0-20200406125435-ad6a9003139e
 	github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775
 	github.com/cilium/ipam v0.0.0-20200420133938-2f672ef3ad54
diff --git a/go.sum b/go.sum
index f85a012d00..0cfa7cf17c 100644
--- a/go.sum
+++ b/go.sum
@@ -107,8 +107,8 @@ github.com/christarazi/structured-merge-diff/v4 v4.0.2-0.20200917183246-1cc60193
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cilium/arping v1.0.1-0.20190728065459-c5eaf8d7a710 h1:htVjkajqUYy6JmLMGlZYxfZ4urQq7rDvgUfmSJX7fSg=
-github.com/cilium/arping v1.0.1-0.20190728065459-c5eaf8d7a710/go.mod h1:ohfPr9hSb4vRsw5UEjCs3OoWD38U0z8EfSgZPbIe/+M=
+github.com/cilium/arping v1.0.1-0.20201009104213-b546132ab753 h1:E0nVFaPUX3dO9zU8dUx15lahVRlpTfP/c6/BzLjNiwc=
+github.com/cilium/arping v1.0.1-0.20201009104213-b546132ab753/go.mod h1:hnjbWhP2F454GKo6vEscP3emePUtB+5ODiGAICLgMzQ=
 github.com/cilium/client-go v0.0.0-20200917084247-85ed8d558b9c h1:SJ3FHtkLpqUfcnn9cYrxJ+By5j1p5yBPv0IojXc9WLk=
 github.com/cilium/client-go v0.0.0-20200917084247-85ed8d558b9c/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA=
 github.com/cilium/deepequal-gen v0.0.0-20200406125435-ad6a9003139e h1:VZolEtS7AlGDu3IH368iqkvfQQSGPgOnPjNaUx4dS7M=
diff --git a/images/operator/Dockerfile b/images/operator/Dockerfile
index 2a27ea7c4c..c007de2a4e 100644
--- a/images/operator/Dockerfile
+++ b/images/operator/Dockerfile
@@ -6,29 +6,31 @@
 ARG CILIUM_BUILDER_IMAGE=docker.io/cilium/cilium-builder-dev:618b6b93c98b3075048861a512fa93525ef3f1f1
 ARG CA_CERTIFICATES_IMAGE=docker.io/cilium/ca-certificates:69a9f5d66ff96bf97e8b9dc107e92aa9ddbdc9a8
 
-FROM --platform=linux/amd64 ${CILIUM_BUILDER_IMAGE} as builder
+FROM ${CILIUM_BUILDER_IMAGE} as builder
 
+ARG TARGETOS
+ARG TARGETARCH
 ARG NOSTRIP
 ARG LOCKDEBUG
 ARG RACE
 
+ENV GOOS=${TARGETOS} \
+  GOARCH=${TARGETARCH}
+
 RUN --mount=type=bind,readwrite,target=/go/src/github.com/cilium/cilium --mount=target=/root/.cache,type=cache --mount=target=/go/pkg/mod,type=cache \
   make -C operator \
-    NOSTRIP=$NOSTRIP LOCKDEBUG=$LOCKDEBUG RACE=$RACE PKG_BUILD=1 \
-  && mkdir -p /out/linux/amd64/usr/bin && mv operator/cilium-operator* /out/linux/amd64/usr/bin
+  NOSTRIP=$NOSTRIP LOCKDEBUG=$LOCKDEBUG RACE=$RACE PKG_BUILD=1 \
+  && mkdir -p /out/${TARGETOS}/${TARGETARCH}/usr/bin && mv operator/cilium-operator* /out/${TARGETOS}/${TARGETARCH}/usr/bin
 
-RUN --mount=type=bind,readwrite,target=/go/src/github.com/cilium/cilium --mount=target=/root/.cache,type=cache --mount=target=/go/pkg/mod,type=cache \
-  env GOARCH=arm64 \
-    make -C operator \
-      NOSTRIP=$NOSTRIP LOCKDEBUG=$LOCKDEBUG RACE=$RACE PKG_BUILD=1 \
-  && mkdir -p /out/linux/arm64/usr/bin && mv operator/cilium-operator* /out/linux/arm64/usr/bin
+FROM ${CA_CERTIFICATES_IMAGE}
 
+ARG TARGETOS
+ARG TARGETARCH
 
-FROM ${CA_CERTIFICATES_IMAGE}
-ARG TARGETPLATFORM
 LABEL maintainer="maintainer@cilium.io"
 
-COPY --from=builder /out/${TARGETPLATFORM} /
-
 WORKDIR /
+
+COPY --from=builder /out/${TARGETOS}/${TARGETARCH} .
+
 CMD ["/usr/bin/cilium-operator-generic"]
diff --git a/jenkinsfiles/kubernetes-upstream.Jenkinsfile b/jenkinsfiles/kubernetes-upstream.Jenkinsfile
index d1b47ed180..5d1baeabac 100644
--- a/jenkinsfiles/kubernetes-upstream.Jenkinsfile
+++ b/jenkinsfiles/kubernetes-upstream.Jenkinsfile
@@ -36,7 +36,8 @@ pipeline {
         TESTDIR="${WORKSPACE}/${PROJ_PATH}/test"
         VM_MEMORY = "5120"
         K8S_VERSION="1.19"
-        SERVER_BOX = "cilium/ubuntu"
+        KERNEL="419"
+        SERVER_BOX = "cilium/ubuntu-4-19"
         CNI_INTEGRATION=setIfLabel("integration/cni-flannel", "FLANNEL", "")
         RACE="""${sh(
                 returnStdout: true,
@@ -104,7 +105,7 @@ pipeline {
 
         stage('BDD-tests'){
             options {
-                timeout(time: 90, unit: 'MINUTES')
+                timeout(time: 150, unit: 'MINUTES')
             }
 
             steps {
diff --git a/pkg/bpf/bpf_linux.go b/pkg/bpf/bpf_linux.go
index ce8ca2d894..6bb699bb4e 100644
--- a/pkg/bpf/bpf_linux.go
+++ b/pkg/bpf/bpf_linux.go
@@ -464,23 +464,31 @@ func objCheck(fd int, path string, mapType MapType, keySize, valueSize, maxEntri
 
 func OpenOrCreateMap(path string, mapType MapType, keySize, valueSize, maxEntries, flags uint32, innerID uint32, pin bool) (int, bool, error) {
 	var fd int
+	var err error
 
 	redo := false
 	isNewMap := false
 
 recreate:
-	if _, err := os.Stat(path); os.IsNotExist(err) || redo {
-		mapDir := filepath.Dir(path)
-		if _, err = os.Stat(mapDir); os.IsNotExist(err) {
-			if err = os.MkdirAll(mapDir, 0755); err != nil {
-				return 0, isNewMap, &os.PathError{
-					Op:   "Unable create map base directory",
-					Path: path,
-					Err:  err,
+	create := true
+	if pin {
+		if _, err := os.Stat(path); os.IsNotExist(err) || redo {
+			mapDir := filepath.Dir(path)
+			if _, err = os.Stat(mapDir); os.IsNotExist(err) {
+				if err = os.MkdirAll(mapDir, 0755); err != nil {
+					return 0, isNewMap, &os.PathError{
+						Op:   "Unable create map base directory",
+						Path: path,
+						Err:  err,
+					}
 				}
 			}
+		} else {
+			create = false
 		}
+	}
 
+	if create {
 		fd, err = CreateMap(
 			mapType,
 			keySize,
@@ -515,7 +523,7 @@ recreate:
 		return fd, isNewMap, nil
 	}
 
-	fd, err := ObjGet(path)
+	fd, err = ObjGet(path)
 	if err == nil {
 		redo = objCheck(
 			fd,
diff --git a/pkg/bpf/map_linux.go b/pkg/bpf/map_linux.go
index 535490e609..7596d48c59 100644
--- a/pkg/bpf/map_linux.go
+++ b/pkg/bpf/map_linux.go
@@ -467,13 +467,13 @@ func (m *Map) OpenOrCreate() (bool, error) {
 	return m.openOrCreate(true)
 }
 
-// OpenOrCreateUnpinned is similar to OpenOrCreate (see above) but without
-// pinning the map to the file system if it had to be created.
-func (m *Map) OpenOrCreateUnpinned() (bool, error) {
+// CreateUnpinned creates the map without pinning it to the file system.
+func (m *Map) CreateUnpinned() error {
 	m.lock.Lock()
 	defer m.lock.Unlock()
 
-	return m.openOrCreate(false)
+	_, err := m.openOrCreate(false)
+	return err
 }
 
 // Create is similar to OpenOrCreate, but closes the map after creating or
diff --git a/pkg/comparator/comparator.go b/pkg/comparator/comparator.go
index 7c8cde61a7..ccf1192744 100644
--- a/pkg/comparator/comparator.go
+++ b/pkg/comparator/comparator.go
@@ -1,4 +1,4 @@
-// Copyright 2017-2018 Authors of Cilium
+// Copyright 2017-2020 Authors of Cilium
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -78,3 +78,43 @@ func MapBoolEquals(m1, m2 map[string]bool) bool {
 	}
 	return true
 }
+
+// MapStringEqualsIgnoreKeys returns true if both maps have the same values for
+// the keys that are not present in the 'ignoreKeys'.
+func MapStringEqualsIgnoreKeys(m1, m2 map[string]string, ignoreKeys []string) bool {
+	switch {
+	case m1 == nil && m2 == nil:
+		return true
+	case m1 == nil && m2 != nil,
+		m1 != nil && m2 == nil:
+		return false
+	}
+	ignoredM1 := 0
+	for k1, v1 := range m1 {
+		var ignore bool
+		for _, ig := range ignoreKeys {
+			if k1 == ig {
+				ignore = true
+				break
+			}
+		}
+		if ignore {
+			ignoredM1++
+			continue
+		}
+		if v2, ok := m2[k1]; !ok || v2 != v1 {
+			return false
+		}
+	}
+
+	ignoredM2 := 0
+	for _, ig := range ignoreKeys {
+		if _, ok := m2[ig]; ok {
+			ignoredM2++
+		}
+	}
+	if len(m1)-ignoredM1 != len(m2)-ignoredM2 {
+		return false
+	}
+	return true
+}
diff --git a/pkg/hubble/api/v1/interface.go b/pkg/hubble/api/v1/interface.go
index fc7ba34927..9432dd89b9 100644
--- a/pkg/hubble/api/v1/interface.go
+++ b/pkg/hubble/api/v1/interface.go
@@ -46,6 +46,7 @@ type Flow interface {
 	GetTrafficDirection() flowpb.TrafficDirection
 	GetPolicyMatchType() uint32
 	GetSummary() string
+	GetDropReasonDesc() flowpb.DropReason
 }
 
 // This ensures that the protobuf definition implements the interface
diff --git a/pkg/hubble/parser/seven/parser.go b/pkg/hubble/parser/seven/parser.go
index cd77b416ca..6a0b5ef47d 100644
--- a/pkg/hubble/parser/seven/parser.go
+++ b/pkg/hubble/parser/seven/parser.go
@@ -72,6 +72,9 @@ func New(log logrus.FieldLogger, dnsGetter getters.DNSGetter, ipGetter getters.I
 
 // Decode decodes the data from 'payload' into 'decoded'
 func (p *Parser) Decode(r *accesslog.LogRecord, decoded *pb.Flow) error {
+	// Safety: This function and all the helpers it invokes are not allowed to
+	// mutate r in any way. We only have read access to the LogRecord, as it
+	// may be shared with other consumers
 	if r == nil {
 		return errors.ErrEmptyData
 	}
@@ -129,6 +132,7 @@ func (p *Parser) Decode(r *accesslog.LogRecord, decoded *pb.Flow) error {
 	decoded.Time = pbTimestamp
 	decoded.Verdict = decodeVerdict(r.Verdict)
 	decoded.DropReason = 0
+	decoded.DropReasonDesc = pb.DropReason_DROP_REASON_UNKNOWN
 	decoded.IP = ip
 	decoded.L4 = l4
 	decoded.Source = decodeEndpoint(sourceEndpoint, sourceNamespace, sourcePod)
@@ -265,7 +269,10 @@ func decodeLayer4(protocol accesslog.TransportProtocol, source, destination acce
 }
 
 func decodeEndpoint(endpoint accesslog.EndpointInfo, namespace, podName string) *pb.Endpoint {
-	labels := endpoint.Labels
+	// Safety: We only have read access to endpoint, therefore we need to create
+	// a copy of the label list before we can sort it
+	labels := make([]string, len(endpoint.Labels))
+	copy(labels, endpoint.Labels)
 	sort.Strings(labels)
 	return &pb.Endpoint{
 		ID:        uint32(endpoint.ID),
diff --git a/pkg/hubble/parser/threefour/parser.go b/pkg/hubble/parser/threefour/parser.go
index 9d971d797d..c890bc2ef6 100644
--- a/pkg/hubble/parser/threefour/parser.go
+++ b/pkg/hubble/parser/threefour/parser.go
@@ -173,6 +173,7 @@ func (p *Parser) Decode(data []byte, decoded *pb.Flow) error {
 
 	decoded.Verdict = decodeVerdict(dn, tn, pvn)
 	decoded.DropReason = decodeDropReason(dn, pvn)
+	decoded.DropReasonDesc = pb.DropReason(decoded.DropReason)
 	decoded.Ethernet = ether
 	decoded.IP = ip
 	decoded.L4 = l4
diff --git a/pkg/hubble/relay/pool/option.go b/pkg/hubble/relay/pool/option.go
index 42037dfd97..27abf0ccdd 100644
--- a/pkg/hubble/relay/pool/option.go
+++ b/pkg/hubble/relay/pool/option.go
@@ -39,6 +39,11 @@ var defaultOptions = options{
 		Options: []grpc.DialOption{
 			grpc.WithInsecure(),
 			grpc.WithBlock(),
+			grpc.FailOnNonTempDialError(true),
+			// TODO: uncomment the line below once grpc-go is >= v1.30.0
+			// currently blocked on v1.29.1, see the following PR for details
+			// https://github.com/cilium/cilium/pull/13405
+			// grpc.WithReturnConnectionError(),
 		},
 	},
 	backoff: &backoff.Exponential{
diff --git a/pkg/hubble/relay/server/server.go b/pkg/hubble/relay/server/server.go
index 9276e355bd..557601eeb7 100644
--- a/pkg/hubble/relay/server/server.go
+++ b/pkg/hubble/relay/server/server.go
@@ -75,8 +75,15 @@ func New(options ...Option) (*Server, error) {
 		),
 		pool.WithClientConnBuilder(pool.GRPCClientConnBuilder{
 			DialTimeout: opts.dialTimeout,
-			Options:     []grpc.DialOption{grpc.WithBlock()},
-			TLSConfig:   opts.clientTLSConfig,
+			Options: []grpc.DialOption{
+				grpc.WithBlock(),
+				grpc.FailOnNonTempDialError(true),
+				// TODO: uncomment the line below once grpc-go is >= v1.30.0
+				// currently blocked on v1.29.1, see the following PR for details
+				// https://github.com/cilium/cilium/pull/13405
+				// grpc.WithReturnConnectionError(),
+			},
+			TLSConfig: opts.clientTLSConfig,
 		}),
 		pool.WithRetryTimeout(opts.retryTimeout),
 		pool.WithLogger(opts.log),
diff --git a/pkg/ipam/allocator/podcidr/podcidr.go b/pkg/ipam/allocator/podcidr/podcidr.go
index 207aaeb25a..7b45c1942e 100644
--- a/pkg/ipam/allocator/podcidr/podcidr.go
+++ b/pkg/ipam/allocator/podcidr/podcidr.go
@@ -836,7 +836,7 @@ func (n *NodesPodCIDRManager) allocateNext(nodeName string) (*nodeCIDRs, bool, e
 			return nil, false, err
 		}
 		revertStack.Push(revertFunc)
-		log.Debug("v4CIDR", v4CIDR)
+		log.WithField("CIDR", v4CIDR).Debug("v4 allocated CIDR")
 		nCIDRs.v4PodCIDRs = []*net.IPNet{v4CIDR}
 	}
 	if len(n.v6CIDRAllocators) != 0 {
@@ -845,7 +845,7 @@ func (n *NodesPodCIDRManager) allocateNext(nodeName string) (*nodeCIDRs, bool, e
 			return nil, false, err
 		}
 		revertStack.Push(revertFunc)
-		log.Debug("v6CIDR", v6CIDR)
+		log.WithField("CIDR", v6CIDR).Debug("v6 allocated CIDR")
 		nCIDRs.v6PodCIDRs = []*net.IPNet{v6CIDR}
 	}
 
diff --git a/pkg/k8s/apis/cilium.io/v2/clrp_types.go b/pkg/k8s/apis/cilium.io/v2/clrp_types.go
index fc49c240c1..7a3aff6d70 100644
--- a/pkg/k8s/apis/cilium.io/v2/clrp_types.go
+++ b/pkg/k8s/apis/cilium.io/v2/clrp_types.go
@@ -234,11 +234,6 @@ func (pInfo *PortInfo) SanitizePortInfo(checkNamedPort bool) (uint16, string, lb
 	}
 	pName = strings.ToLower(pInfo.Name) // Normalize for case insensitive comparison
 
-	// Sanitize protocol
-	var err error
-	protocol, err = lb.NewL4Type(string(pInfo.Protocol))
-	if err != nil {
-		return pInt, pName, protocol, err
-	}
+	protocol = lb.NewL4Type(string(pInfo.Protocol))
 	return pInt, pName, protocol, nil
 }
diff --git a/pkg/k8s/apis/cilium.io/v2/cnp_types.go b/pkg/k8s/apis/cilium.io/v2/cnp_types.go
index 03d3c03ebc..1f43629671 100644
--- a/pkg/k8s/apis/cilium.io/v2/cnp_types.go
+++ b/pkg/k8s/apis/cilium.io/v2/cnp_types.go
@@ -80,21 +80,11 @@ func sharedCNPDeepEqual(in, other *CiliumNetworkPolicy) bool {
 		return false
 	}
 
-	// Ignore v1.LastAppliedConfigAnnotation annotation
-	lastAppliedCfgAnnotation1, ok1 := in.GetAnnotations()[v1.LastAppliedConfigAnnotation]
-	lastAppliedCfgAnnotation2, ok2 := other.GetAnnotations()[v1.LastAppliedConfigAnnotation]
-	defer func() {
-		if ok1 && in.GetAnnotations() != nil {
-			in.GetAnnotations()[v1.LastAppliedConfigAnnotation] = lastAppliedCfgAnnotation1
-		}
-		if ok2 && other.GetAnnotations() != nil {
-			other.GetAnnotations()[v1.LastAppliedConfigAnnotation] = lastAppliedCfgAnnotation2
-		}
-	}()
-	delete(in.GetAnnotations(), v1.LastAppliedConfigAnnotation)
-	delete(other.GetAnnotations(), v1.LastAppliedConfigAnnotation)
-
-	return comparator.MapStringEquals(in.GetAnnotations(), other.GetAnnotations())
+	return comparator.MapStringEqualsIgnoreKeys(
+		in.GetAnnotations(),
+		other.GetAnnotations(),
+		// Ignore v1.LastAppliedConfigAnnotation annotation
+		[]string{v1.LastAppliedConfigAnnotation})
 }
 
 // +deepequal-gen=true
diff --git a/pkg/k8s/cnp.go b/pkg/k8s/cnp.go
index 41f4ec7688..732704fd58 100644
--- a/pkg/k8s/cnp.go
+++ b/pkg/k8s/cnp.go
@@ -140,11 +140,8 @@ func (c *CNPStatusUpdateContext) prepareUpdate(cnp *types.SlimCNP, scopedLog *lo
 		return
 	}
 
-	// Make a copy since the rule is a pointer, and any of its fields
-	// which are also pointers could be modified outside of this
-	// function or with the 'cnp.Parse()' which can also overwrite fields.
-	serverRule = cnp.DeepCopy()
-	_, err = serverRule.Parse()
+	serverRule = cnp
+	_, err = cnp.Parse()
 	if err != nil {
 		log.WithError(err).WithField(logfields.Object, logfields.Repr(serverRule)).
 			Warn("Error parsing new CiliumNetworkPolicy rule")
diff --git a/pkg/k8s/service.go b/pkg/k8s/service.go
index 09a6b3db4a..35e7030abf 100644
--- a/pkg/k8s/service.go
+++ b/pkg/k8s/service.go
@@ -442,18 +442,6 @@ func NewService(ip net.IP, externalIPs, loadBalancerIPs, loadBalancerSourceRange
 	}
 }
 
-// UniquePorts returns a map of all unique ports configured in the service
-func (s *Service) UniquePorts() map[uint16]bool {
-	// We are not discriminating the different L4 protocols on the same L4
-	// port so we create the number of unique sets of service IP + service
-	// port.
-	uniqPorts := map[uint16]bool{}
-	for _, p := range s.Ports {
-		uniqPorts[p.Port] = true
-	}
-	return uniqPorts
-}
-
 // NewClusterService returns the serviceStore.ClusterService representing a
 // Kubernetes Service
 func NewClusterService(id ServiceID, k8sService *Service, k8sEndpoints *Endpoints) serviceStore.ClusterService {
diff --git a/pkg/k8s/service_cache.go b/pkg/k8s/service_cache.go
index 7731451ef0..e47c725896 100644
--- a/pkg/k8s/service_cache.go
+++ b/pkg/k8s/service_cache.go
@@ -341,28 +341,6 @@ func (s *ServiceCache) DeleteEndpointSlices(epSlice *slim_discovery_v1beta1.Endp
 // FrontendList is the list of all k8s service frontends
 type FrontendList map[string]struct{}
 
-// LooseMatch returns true if the provided frontend is found in the
-// FrontendList. If the frontend has a protocol value set, it only matches a
-// k8s service with a matching protocol. If no protocol is set, any k8s service
-// matching frontend IP and port is considered a match, regardless of protocol.
-func (l FrontendList) LooseMatch(frontend loadbalancer.L3n4Addr) (exists bool) {
-	switch frontend.Protocol {
-	case loadbalancer.NONE:
-		for _, protocol := range loadbalancer.AllProtocols {
-			frontend.Protocol = protocol
-			_, exists = l[frontend.StringWithProtocol()]
-			if exists {
-				return
-			}
-		}
-
-	// If the protocol is set, perform an exact match
-	default:
-		_, exists = l[frontend.StringWithProtocol()]
-	}
-	return
-}
-
 // UniqueServiceFrontends returns all externally scoped services known to
 // the service cache as a map, indexed by the string representation of a
 // loadbalancer.L3n4Addr. This helper is only used in unit tests.
@@ -379,12 +357,12 @@ func (s *ServiceCache) UniqueServiceFrontends() FrontendList {
 				L4Addr: *p,
 				Scope:  loadbalancer.ScopeExternal,
 			}
-			uniqueFrontends[address.StringWithProtocol()] = struct{}{}
+			uniqueFrontends[address.String()] = struct{}{}
 		}
 		for _, nodePortFEs := range svc.NodePorts {
 			for _, fe := range nodePortFEs {
 				if fe.Scope == loadbalancer.ScopeExternal {
-					uniqueFrontends[fe.StringWithProtocol()] = struct{}{}
+					uniqueFrontends[fe.String()] = struct{}{}
 				}
 			}
 		}
diff --git a/pkg/k8s/watchers/cilium_network_policy.go b/pkg/k8s/watchers/cilium_network_policy.go
index 15f6fe5de6..18509b7e41 100644
--- a/pkg/k8s/watchers/cilium_network_policy.go
+++ b/pkg/k8s/watchers/cilium_network_policy.go
@@ -301,24 +301,28 @@ func (k *K8sWatcher) updateCiliumNetworkPolicyV2(ciliumNPClient clientset.Interf
 
 	// Do not add rule into policy repository if the spec remains unchanged.
 	if !option.Config.DisableCNPStatusUpdates {
-		if !oldRuleCpy.AnnotationsEquals(newRuleCpy.CiliumNetworkPolicy) {
-
-			// Update annotations within a controller so the status of the update
-			// is trackable from the list of running controllers, and so we do
-			// not block subsequent policy lifecycle operations from Kubernetes
-			// until the update is complete.
-			oldCtrlName := oldRuleCpy.GetControllerName()
-			newCtrlName := newRuleCpy.GetControllerName()
-
-			// In case the controller name changes between copies of rules,
-			// remove old controller so we do not leak goroutines.
-			if oldCtrlName != newCtrlName {
-				err := k8sCM.RemoveController(oldCtrlName)
-				if err != nil {
-					log.Debugf("Unable to remove controller %s: %s", oldCtrlName, err)
+		if oldRuleCpy.Spec.DeepEqual(newRuleCpy.CiliumNetworkPolicy.Spec) &&
+			oldRuleCpy.Specs.DeepEqual(&newRuleCpy.CiliumNetworkPolicy.Specs) {
+			if !oldRuleCpy.AnnotationsEquals(newRuleCpy.CiliumNetworkPolicy) {
+
+				// Update annotations within a controller so the status of the update
+				// is trackable from the list of running controllers, and so we do
+				// not block subsequent policy lifecycle operations from Kubernetes
+				// until the update is complete.
+				oldCtrlName := oldRuleCpy.GetControllerName()
+				newCtrlName := newRuleCpy.GetControllerName()
+
+				// In case the controller name changes between copies of rules,
+				// remove old controller so we do not leak goroutines.
+				if oldCtrlName != newCtrlName {
+					err := k8sCM.RemoveController(oldCtrlName)
+					if err != nil {
+						log.Debugf("Unable to remove controller %s: %s", oldCtrlName, err)
+					}
 				}
+				k.updateCiliumNetworkPolicyV2AnnotationsOnly(ciliumNPClient, ciliumV2Store, newRuleCpy)
 			}
-			k.updateCiliumNetworkPolicyV2AnnotationsOnly(ciliumNPClient, ciliumV2Store, newRuleCpy)
+			return nil
 		}
 	}
 
diff --git a/pkg/k8s/watchers/pod.go b/pkg/k8s/watchers/pod.go
index 2f1c4683cb..af79d1fb08 100644
--- a/pkg/k8s/watchers/pod.go
+++ b/pkg/k8s/watchers/pod.go
@@ -483,13 +483,9 @@ func (k *K8sWatcher) genServiceMappings(pod *slim_corev1.Pod, podIPs []string, l
 				continue
 			}
 
-			proto, err := loadbalancer.NewL4Type(string(p.Protocol))
-			if err != nil {
-				continue
-			}
-
 			var bes4 []loadbalancer.Backend
 			var bes6 []loadbalancer.Backend
+			proto := loadbalancer.NewL4Type(string(p.Protocol))
 
 			for _, podIP := range podIPs {
 				be := loadbalancer.Backend{
diff --git a/pkg/k8s/watchers/watcher.go b/pkg/k8s/watchers/watcher.go
index fe986515c4..7be8255f06 100644
--- a/pkg/k8s/watchers/watcher.go
+++ b/pkg/k8s/watchers/watcher.go
@@ -605,16 +605,8 @@ func (k *K8sWatcher) delK8sSVCs(svc k8s.ServiceID, svcInfo *k8s.Service, se *k8s
 		logfields.K8sNamespace: svc.Namespace,
 	})
 
-	repPorts := svcInfo.UniquePorts()
-
 	frontends := []*loadbalancer.L3n4Addr{}
-
 	for portName, svcPort := range svcInfo.Ports {
-		if !repPorts[svcPort.Port] {
-			continue
-		}
-		repPorts[svcPort.Port] = false
-
 		fe := loadbalancer.NewL3n4Addr(svcPort.Protocol, svcInfo.FrontendIP, svcPort.Port, loadbalancer.ScopeExternal)
 		frontends = append(frontends, fe)
 
@@ -728,14 +720,8 @@ func genCartesianProduct(
 
 // datapathSVCs returns all services that should be set in the datapath.
 func datapathSVCs(svc *k8s.Service, endpoints *k8s.Endpoints) (svcs []loadbalancer.SVC) {
-	uniqPorts := svc.UniquePorts()
-
 	clusterIPPorts := map[loadbalancer.FEPortName]*loadbalancer.L4Addr{}
 	for fePortName, fePort := range svc.Ports {
-		if !uniqPorts[fePort.Port] {
-			continue
-		}
-		uniqPorts[fePort.Port] = false
 		clusterIPPorts[fePortName] = fePort
 	}
 	if svc.FrontendIP != nil {
@@ -845,6 +831,7 @@ func (k *K8sWatcher) addK8sSVCs(svcID k8s.ServiceID, oldSvc, svc *k8s.Service, e
 			Name:                      svcID.Name,
 			Namespace:                 svcID.Namespace,
 		}
+		log.WithField(logfields.Object, logfields.Repr(*p)).Debug("upserting loadbalancer repr")
 		if _, _, err := k.svcManager.UpsertService(p); err != nil {
 			scopedLog.WithError(err).Error("Error while inserting service in LB map")
 		}
diff --git a/pkg/loadbalancer/loadbalancer.go b/pkg/loadbalancer/loadbalancer.go
index 508c392aff..4dd2b623ff 100644
--- a/pkg/loadbalancer/loadbalancer.go
+++ b/pkg/loadbalancer/loadbalancer.go
@@ -160,6 +160,7 @@ func (s ServiceFlags) UInt16() uint16 {
 }
 
 const (
+	// NONE type.
 	NONE = L4Type("NONE")
 	// TCP type.
 	TCP = L4Type("TCP")
@@ -265,14 +266,25 @@ func (s *SVC) GetModel() *models.Service {
 	}
 }
 
-func NewL4Type(name string) (L4Type, error) {
+func NewL4Type(name string) L4Type {
 	switch strings.ToLower(name) {
 	case "tcp":
-		return TCP, nil
+		return TCP
 	case "udp":
-		return UDP, nil
+		return UDP
 	default:
-		return "", fmt.Errorf("unknown L4 protocol")
+		return NONE
+	}
+}
+
+func NewL4TypeFromNumber(proto uint8) L4Type {
+	switch proto {
+	case 6:
+		return TCP
+	case 17:
+		return UDP
+	default:
+		return NONE
 	}
 }
 
@@ -307,6 +319,11 @@ func (l *L4Addr) DeepCopy() *L4Addr {
 	}
 }
 
+// String returns a string representation of an L4Addr
+func (l *L4Addr) String() string {
+	return fmt.Sprintf("%d/%s", l.Port, l.Protocol)
+}
+
 // L3n4Addr is used to store, as an unique L3+L4 address in the KVStore. It also
 // includes the lookup scope for frontend addresses which is used in service
 // handling for externalTrafficPolicy=Local, that is, Scope{External,Internal}.
@@ -336,16 +353,9 @@ func NewL3n4AddrFromModel(base *models.FrontendAddress) (*L3n4Addr, error) {
 		return nil, fmt.Errorf("missing IP address")
 	}
 
-	proto := NONE
-	if base.Protocol != "" {
-		p, err := NewL4Type(base.Protocol)
-		if err != nil {
-			return nil, err
-		}
-		proto = p
-	}
+	p := NewL4Type(base.Protocol)
 
-	l4addr := NewL4Addr(proto, base.Port)
+	l4addr := NewL4Addr(p, base.Port)
 	ip := net.ParseIP(base.IP)
 	if ip == nil {
 		return nil, fmt.Errorf("invalid IP address \"%s\"", base.IP)
@@ -378,8 +388,8 @@ func NewBackendFromBackendModel(base *models.BackendAddress) (*Backend, error) {
 		return nil, fmt.Errorf("missing IP address")
 	}
 
-	// FIXME: Should this be NONE ?
-	l4addr := NewL4Addr(NONE, base.Port)
+	p := NewL4Type(base.Protocol)
+	l4addr := NewL4Addr(p, base.Port)
 	ip := net.ParseIP(*base.IP)
 	if ip == nil {
 		return nil, fmt.Errorf("invalid IP address \"%s\"", *base.IP)
@@ -393,8 +403,8 @@ func NewL3n4AddrFromBackendModel(base *models.BackendAddress) (*L3n4Addr, error)
 		return nil, fmt.Errorf("missing IP address")
 	}
 
-	// FIXME: Should this be NONE ?
-	l4addr := NewL4Addr(NONE, base.Port)
+	p := NewL4Type(base.Protocol)
+	l4addr := NewL4Addr(p, base.Port)
 	ip := net.ParseIP(*base.IP)
 	if ip == nil {
 		return nil, fmt.Errorf("invalid IP address \"%s\"", *base.IP)
@@ -412,9 +422,10 @@ func (a *L3n4Addr) GetModel() *models.FrontendAddress {
 		scope = models.FrontendAddressScopeInternal
 	}
 	return &models.FrontendAddress{
-		IP:    a.IP.String(),
-		Port:  a.Port,
-		Scope: scope,
+		IP:       a.IP.String(),
+		Port:     a.Port,
+		Scope:    scope,
+		Protocol: a.Protocol,
 	}
 }
 
@@ -428,25 +439,13 @@ func (b *Backend) GetBackendModel() *models.BackendAddress {
 		IP:       &ip,
 		Port:     b.Port,
 		NodeName: b.NodeName,
+		Protocol: b.Protocol,
 	}
 }
 
-// String returns the L3n4Addr in the "IPv4:Port[/Scope]" format for IPv4 and
-// "[IPv6]:Port[/Scope]" format for IPv6.
+// String returns the L3n4Addr in the "IPv4:Port/Protocol[/Scope]" format for IPv4 and
+// "[IPv6]:Port/Protocol[/Scope]" format for IPv6.
 func (a *L3n4Addr) String() string {
-	var scope string
-	if a.Scope == ScopeInternal {
-		scope = "/i"
-	}
-	if a.IsIPv6() {
-		return fmt.Sprintf("[%s]:%d%s", a.IP.String(), a.Port, scope)
-	}
-	return fmt.Sprintf("%s:%d%s", a.IP.String(), a.Port, scope)
-}
-
-// StringWithProtocol returns the L3n4Addr in the "IPv4:Port/Protocol[/Scope]"
-// format for IPv4 and "[IPv6]:Port/Protocol[/Scope]" format for IPv6.
-func (a *L3n4Addr) StringWithProtocol() string {
 	var scope string
 	if a.Scope == ScopeInternal {
 		scope = "/i"
@@ -477,14 +476,7 @@ func (a *L3n4Addr) DeepCopy() *L3n4Addr {
 
 // Hash calculates L3n4Addr's internal SHA256Sum.
 func (a L3n4Addr) Hash() string {
-	// FIXME: Remove Protocol's omission once we care about protocols.
-	protoBak := a.Protocol
-	a.Protocol = ""
-	defer func() {
-		a.Protocol = protoBak
-	}()
-
-	str := []byte(fmt.Sprintf("%+v", a))
+	str := []byte(fmt.Sprintf("%s", a.String()))
 	return fmt.Sprintf("%x", sha512.Sum512_256(str))
 }
 
diff --git a/pkg/maps/lbmap/ipv4.go b/pkg/maps/lbmap/ipv4.go
index bc2751e1bd..523f20f908 100644
--- a/pkg/maps/lbmap/ipv4.go
+++ b/pkg/maps/lbmap/ipv4.go
@@ -171,11 +171,28 @@ func NewService4Key(ip net.IP, port uint16, proto u8proto.U8proto, scope uint8,
 }
 
 func (k *Service4Key) String() string {
-	addr := net.JoinHostPort(k.Address.String(), fmt.Sprintf("%d", k.Port))
-	if k.Scope == loadbalancer.ScopeInternal {
-		addr += "/i"
+	return serviceKey(
+		k.Address.String(),
+		k.Port,
+		k.GetProtocol(),
+		k.Scope == loadbalancer.ScopeInternal,
+	)
+}
+
+func serviceKey(address string, port uint16, protocol uint8, internal bool) string {
+	a := net.JoinHostPort(address, fmt.Sprintf("%d", port))
+
+	p, err := u8proto.FromNumber(protocol)
+	if err != nil {
+		p = u8proto.ANY
+	}
+
+	var i string
+	if internal {
+		i = "/i"
 	}
-	return addr
+
+	return fmt.Sprintf("%s/%s%s", a, p, i)
 }
 
 func (k *Service4Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
@@ -189,6 +206,7 @@ func (k *Service4Key) SetScope(scope uint8)      { k.Scope = scope }
 func (k *Service4Key) GetScope() uint8           { return k.Scope }
 func (k *Service4Key) GetAddress() net.IP        { return k.Address.IP() }
 func (k *Service4Key) GetPort() uint16           { return k.Port }
+func (k *Service4Key) GetProtocol() uint8        { return k.Proto }
 func (k *Service4Key) MapDelete() error          { return k.Map().Delete(k.ToNetwork()) }
 
 func (k *Service4Key) RevNatValue() RevNatValue {
@@ -313,6 +331,7 @@ func (v *Backend4Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v)
 
 func (b *Backend4Value) GetAddress() net.IP { return b.Address.IP() }
 func (b *Backend4Value) GetPort() uint16    { return b.Port }
+func (b *Backend4Value) GetProtocol() uint8 { return uint8(b.Proto) }
 
 func (v *Backend4Value) ToNetwork() BackendValue {
 	n := *v
diff --git a/pkg/maps/lbmap/ipv6.go b/pkg/maps/lbmap/ipv6.go
index 25b3a96cbb..1d20e2dba8 100644
--- a/pkg/maps/lbmap/ipv6.go
+++ b/pkg/maps/lbmap/ipv6.go
@@ -164,11 +164,12 @@ func NewService6Key(ip net.IP, port uint16, proto u8proto.U8proto, scope uint8,
 }
 
 func (k *Service6Key) String() string {
-	if k.Scope == loadbalancer.ScopeInternal {
-		return fmt.Sprintf("[%s]:%d/i", k.Address, k.Port)
-	} else {
-		return fmt.Sprintf("[%s]:%d", k.Address, k.Port)
-	}
+	return serviceKey(
+		k.Address.String(),
+		k.Port,
+		k.GetProtocol(),
+		k.Scope == loadbalancer.ScopeInternal,
+	)
 }
 
 func (k *Service6Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
@@ -182,6 +183,7 @@ func (k *Service6Key) SetScope(scope uint8)      { k.Scope = scope }
 func (k *Service6Key) GetScope() uint8           { return k.Scope }
 func (k *Service6Key) GetAddress() net.IP        { return k.Address.IP() }
 func (k *Service6Key) GetPort() uint16           { return k.Port }
+func (k *Service6Key) GetProtocol() uint8        { return k.Proto }
 func (k *Service6Key) MapDelete() error          { return k.Map().Delete(k.ToNetwork()) }
 
 func (k *Service6Key) RevNatValue() RevNatValue {
@@ -297,6 +299,7 @@ func (v *Backend6Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v)
 
 func (b *Backend6Value) GetAddress() net.IP { return b.Address.IP() }
 func (b *Backend6Value) GetPort() uint16    { return b.Port }
+func (b *Backend6Value) GetProtocol() uint8 { return uint8(b.Proto) }
 
 func (v *Backend6Value) ToNetwork() BackendValue {
 	n := *v
diff --git a/pkg/maps/lbmap/lbmap.go b/pkg/maps/lbmap/lbmap.go
index d8f74528b5..b04c77d6a7 100644
--- a/pkg/maps/lbmap/lbmap.go
+++ b/pkg/maps/lbmap/lbmap.go
@@ -17,6 +17,7 @@ package lbmap
 import (
 	"fmt"
 	"net"
+	"sort"
 	"strconv"
 
 	"github.com/cilium/cilium/pkg/bpf"
@@ -63,6 +64,7 @@ type UpsertServiceParams struct {
 	ID                        uint16
 	IP                        net.IP
 	Port                      uint16
+	Protocol                  string
 	Backends                  map[string]uint16
 	PrevBackendCount          int
 	IPv6                      bool
@@ -89,10 +91,15 @@ func (lbmap *LBBPFMap) UpsertService(p *UpsertServiceParams) error {
 		return fmt.Errorf("Invalid svc ID 0")
 	}
 
+	proto, err := u8proto.ParseProtocol(p.Protocol)
+	if err != nil {
+		return err
+	}
+
 	if p.IPv6 {
-		svcKey = NewService6Key(p.IP, p.Port, u8proto.ANY, p.Scope, 0)
+		svcKey = NewService6Key(p.IP, p.Port, proto, p.Scope, 0)
 	} else {
-		svcKey = NewService4Key(p.IP, p.Port, u8proto.ANY, p.Scope, 0)
+		svcKey = NewService4Key(p.IP, p.Port, proto, p.Scope, 0)
 	}
 
 	slot := 1
@@ -103,6 +110,11 @@ func (lbmap *LBBPFMap) UpsertService(p *UpsertServiceParams) error {
 		for name := range p.Backends {
 			backendNames = append(backendNames, name)
 		}
+		// Maglev algorithm might produce different lookup table for the same
+		// set of backends listed in a different order. To avoid that sort
+		// backends by name, as the names are the same on all nodes (in opposite
+		// to backend IDs which are node-local).
+		sort.Strings(backendNames)
 		table := maglev.GetLookupTable(backendNames, lbmap.maglevTableSize)
 		for i, pos := range table {
 			lbmap.maglevBackendIDsBuffer[i] = p.Backends[backendNames[pos]]
@@ -170,12 +182,16 @@ func (*LBBPFMap) DeleteService(svc loadbalancer.L3n4AddrID, backendCount int, us
 		return fmt.Errorf("Invalid svc ID 0")
 	}
 
+	proto, err := u8proto.ParseProtocol(string(svc.Protocol))
+	if err != nil {
+		return err
+	}
 	ipv6 := svc.IsIPv6()
 	if ipv6 {
-		svcKey = NewService6Key(svc.IP, svc.Port, u8proto.ANY, svc.Scope, 0)
+		svcKey = NewService6Key(svc.IP, svc.Port, proto, svc.Scope, 0)
 		revNATKey = NewRevNat6Key(uint16(svc.ID))
 	} else {
-		svcKey = NewService4Key(svc.IP, svc.Port, u8proto.ANY, svc.Scope, 0)
+		svcKey = NewService4Key(svc.IP, svc.Port, proto, svc.Scope, 0)
 		revNATKey = NewRevNat4Key(uint16(svc.ID))
 	}
 
@@ -200,7 +216,7 @@ func (*LBBPFMap) DeleteService(svc loadbalancer.L3n4AddrID, backendCount int, us
 }
 
 // AddBackend adds a backend into a BPF map.
-func (*LBBPFMap) AddBackend(id uint16, ip net.IP, port uint16, ipv6 bool) error {
+func (*LBBPFMap) AddBackend(id uint16, ip net.IP, protocol loadbalancer.L4Type, port uint16, ipv6 bool) error {
 	var (
 		backend Backend
 		err     error
@@ -210,10 +226,14 @@ func (*LBBPFMap) AddBackend(id uint16, ip net.IP, port uint16, ipv6 bool) error
 		return fmt.Errorf("Invalid backend ID 0")
 	}
 
+	p, err := u8proto.ParseProtocol(string(protocol))
+	if err != nil {
+		return err
+	}
 	if ipv6 {
-		backend, err = NewBackend6(loadbalancer.BackendID(id), ip, port, u8proto.ANY)
+		backend, err = NewBackend6(loadbalancer.BackendID(id), ip, port, p)
 	} else {
-		backend, err = NewBackend4(loadbalancer.BackendID(id), ip, port, u8proto.ANY)
+		backend, err = NewBackend4(loadbalancer.BackendID(id), ip, port, p)
 	}
 	if err != nil {
 		return fmt.Errorf("Unable to create backend (%d, %s, %d, %t): %s",
@@ -467,7 +487,7 @@ func (*LBBPFMap) DumpBackendMaps() ([]*loadbalancer.Backend, error) {
 	for backendID, backendVal := range backendValueMap {
 		ip := backendVal.GetAddress()
 		port := backendVal.GetPort()
-		proto := loadbalancer.NONE
+		proto := loadbalancer.NewL4TypeFromNumber(backendVal.GetProtocol())
 		lbBackend := loadbalancer.NewBackend(backendID, proto, ip, port)
 		lbBackends = append(lbBackends, lbBackend)
 	}
diff --git a/pkg/maps/lbmap/lbmap_mock.go b/pkg/maps/lbmap/lbmap_mock.go
index 969b867c0a..c3aa4022f5 100644
--- a/pkg/maps/lbmap/lbmap_mock.go
+++ b/pkg/maps/lbmap/lbmap_mock.go
@@ -19,6 +19,7 @@ import (
 	"net"
 
 	"github.com/cilium/cilium/pkg/cidr"
+	"github.com/cilium/cilium/pkg/loadbalancer"
 	lb "github.com/cilium/cilium/pkg/loadbalancer"
 )
 
@@ -50,7 +51,7 @@ func (m *LBMockMap) UpsertService(p *UpsertServiceParams) error {
 
 	svc, found := m.ServiceByID[p.ID]
 	if !found {
-		frontend := lb.NewL3n4AddrID(lb.NONE, p.IP, p.Port, p.Scope, lb.ID(p.ID))
+		frontend := lb.NewL3n4AddrID(loadbalancer.NewL4Type(p.Protocol), p.IP, p.Port, p.Scope, lb.ID(p.ID))
 		svc = &lb.SVC{Frontend: *frontend}
 	} else {
 		if p.PrevBackendCount != len(svc.Backends) {
@@ -81,12 +82,12 @@ func (m *LBMockMap) DeleteService(addr lb.L3n4AddrID, backendCount int, maglev b
 	return nil
 }
 
-func (m *LBMockMap) AddBackend(id uint16, ip net.IP, port uint16, ipv6 bool) error {
+func (m *LBMockMap) AddBackend(id uint16, ip net.IP, protocol lb.L4Type, port uint16, ipv6 bool) error {
 	if _, found := m.BackendByID[id]; found {
 		return fmt.Errorf("Backend %d already exists", id)
 	}
 
-	m.BackendByID[id] = lb.NewBackend(lb.BackendID(id), lb.NONE, ip, port)
+	m.BackendByID[id] = lb.NewBackend(lb.BackendID(id), protocol, ip, port)
 
 	return nil
 }
diff --git a/pkg/maps/lbmap/maglev.go b/pkg/maps/lbmap/maglev.go
index 9dd0a09d3d..bfd8821a40 100644
--- a/pkg/maps/lbmap/maglev.go
+++ b/pkg/maps/lbmap/maglev.go
@@ -39,7 +39,7 @@ var MaglevOuter6Map *bpf.Map
 
 func InitMaglevMaps(ipv4 bool, ipv6 bool) error {
 	dummyInnerMap := newInnerMaglevMap("cilium_lb_maglev_dummy")
-	if _, err := dummyInnerMap.OpenOrCreateUnpinned(); err != nil {
+	if err := dummyInnerMap.CreateUnpinned(); err != nil {
 		return err
 	}
 	defer dummyInnerMap.Close()
@@ -93,7 +93,7 @@ func updateMaglevTable(ipv6 bool, revNATID uint16, backendIDs []uint16) error {
 	}
 
 	innerMap := newInnerMaglevMap(innerMapName)
-	if _, err := innerMap.OpenOrCreateUnpinned(); err != nil {
+	if err := innerMap.CreateUnpinned(); err != nil {
 		return err
 	}
 	defer innerMap.Close()
diff --git a/pkg/maps/lbmap/types.go b/pkg/maps/lbmap/types.go
index f8eefee7ac..3260ec1d33 100644
--- a/pkg/maps/lbmap/types.go
+++ b/pkg/maps/lbmap/types.go
@@ -53,6 +53,9 @@ type ServiceKey interface {
 	// Get frontend port
 	GetPort() uint16
 
+	// Get protocol
+	GetProtocol() uint8
+
 	// Returns a RevNatValue matching a ServiceKey
 	RevNatValue() RevNatValue
 
@@ -125,6 +128,9 @@ type BackendValue interface {
 	// Get backend port
 	GetPort() uint16
 
+	// Get backend protocol
+	GetProtocol() uint8
+
 	// Convert fields to network byte order.
 	ToNetwork() BackendValue
 }
@@ -168,7 +174,8 @@ type BackendIDByServiceIDSet map[uint16]map[uint16]struct{} // svc ID => backend
 type SourceRangeSetByServiceID map[uint16][]*cidr.CIDR // svc ID => src range CIDRs
 
 func svcFrontend(svcKey ServiceKey, svcValue ServiceValue) *loadbalancer.L3n4AddrID {
-	feL3n4Addr := loadbalancer.NewL3n4Addr(loadbalancer.NONE, svcKey.GetAddress(), svcKey.GetPort(), svcKey.GetScope())
+	p := loadbalancer.NewL4TypeFromNumber(svcKey.GetProtocol())
+	feL3n4Addr := loadbalancer.NewL3n4Addr(p, svcKey.GetAddress(), svcKey.GetPort(), svcKey.GetScope())
 	feL3n4AddrID := &loadbalancer.L3n4AddrID{
 		L3n4Addr: *feL3n4Addr,
 		ID:       loadbalancer.ID(svcValue.GetRevNat()),
@@ -179,7 +186,7 @@ func svcFrontend(svcKey ServiceKey, svcValue ServiceValue) *loadbalancer.L3n4Add
 func svcBackend(backendID loadbalancer.BackendID, backend BackendValue) *loadbalancer.Backend {
 	beIP := backend.GetAddress()
 	bePort := backend.GetPort()
-	beProto := loadbalancer.NONE
-	beBackend := loadbalancer.NewBackend(backendID, beProto, beIP, bePort)
+	p := loadbalancer.NewL4TypeFromNumber(backend.GetProtocol())
+	beBackend := loadbalancer.NewBackend(backendID, p, beIP, bePort)
 	return beBackend
 }
diff --git a/pkg/maps/sockmap/sockmap.go b/pkg/maps/sockmap/sockmap.go
index f6731d7fff..9fa63e017b 100644
--- a/pkg/maps/sockmap/sockmap.go
+++ b/pkg/maps/sockmap/sockmap.go
@@ -23,19 +23,20 @@ import (
 	"github.com/cilium/cilium/pkg/logging"
 	"github.com/cilium/cilium/pkg/logging/logfields"
 	"github.com/cilium/cilium/pkg/types"
+	"github.com/cilium/cilium/pkg/u8proto"
 )
 
 // SockmapKey is the 5-tuple used to lookup a socket
 // +k8s:deepcopy-gen=true
 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey
 type SockmapKey struct {
-	DIP    types.IPv6 `align:"$union0"`
-	SIP    types.IPv6 `align:"$union1"`
-	Family uint8      `align:"family"`
-	Pad7   uint8      `align:"pad7"`
-	Pad8   uint16     `align:"pad8"`
-	SPort  uint32     `align:"sport"`
-	DPort  uint32     `align:"dport"`
+	DIP      types.IPv6 `align:"$union0"`
+	SIP      types.IPv6 `align:"$union1"`
+	Family   uint8      `align:"family"`
+	Protocol uint8      `align:"protocol"`
+	Pad8     uint16     `align:"pad8"`
+	SPort    uint32     `align:"sport"`
+	DPort    uint32     `align:"dport"`
 }
 
 // SockmapValue is the fd of a socket
@@ -47,7 +48,11 @@ type SockmapValue struct {
 
 // String pretty print the 5-tuple as sip:sport->dip:dport
 func (v SockmapKey) String() string {
-	return fmt.Sprintf("%s:%d->%s:%d", v.SIP.String(), v.SPort, v.DIP.String(), v.DPort)
+	p, err := u8proto.FromNumber(v.Protocol)
+	if err != nil {
+		p = u8proto.ANY
+	}
+	return fmt.Sprintf("%s:%d/%s->%s:%d/%s", v.SIP.String(), v.SPort, p, v.DIP.String(), v.DPort, p)
 }
 
 // String pretty print the file descriptor value, note this is local to agent.
diff --git a/pkg/monitor/api/drop.go b/pkg/monitor/api/drop.go
index e07a10c94a..b6d3a167f3 100644
--- a/pkg/monitor/api/drop.go
+++ b/pkg/monitor/api/drop.go
@@ -18,7 +18,7 @@ import (
 	"fmt"
 )
 
-// DropMin numbers below this are non-drop reason codes
+// DropMin numbers less than this are non-drop reason codes
 var DropMin uint8 = 130
 
 // DropInvalid is the Invalid packet reason.
diff --git a/pkg/node/address_darwin.go b/pkg/node/address_darwin.go
index c38d77cf56..b4ba6cee72 100644
--- a/pkg/node/address_darwin.go
+++ b/pkg/node/address_darwin.go
@@ -20,11 +20,11 @@ import (
 	"net"
 )
 
-func firstGlobalV4Addr(intf string, preferredIP net.IP) (net.IP, error) {
+func firstGlobalV4Addr(intf string, preferredIP net.IP, preferPublic bool) (net.IP, error) {
 	return net.IP{}, nil
 }
 
-func firstGlobalV6Addr(intf string, preferredIP net.IP) (net.IP, error) {
+func firstGlobalV6Addr(intf string, preferredIP net.IP, preferPublic bool) (net.IP, error) {
 	return net.IP{}, nil
 }
 
diff --git a/pkg/option/config.go b/pkg/option/config.go
index 54a61ba5bb..1a508e8fbd 100644
--- a/pkg/option/config.go
+++ b/pkg/option/config.go
@@ -1503,7 +1503,7 @@ type DaemonConfig struct {
 	// runs in the same container as Cilium.
 	EnvoyLogPath string
 
-	// EnableSockOps specifies whether to enable sockops (socket lookup).
+	// SockopsEnable specifies whether to enable sockops (socket lookup).
 	SockopsEnable bool
 
 	// PrependIptablesChains is the name of the option to enable prepending
diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go
index d1b81b313b..db7899f195 100644
--- a/pkg/probe/probe.go
+++ b/pkg/probe/probe.go
@@ -72,7 +72,7 @@ func HaveFullLPM() bool {
 			&probeKey{}, int(unsafe.Sizeof(probeKey{})),
 			&probeValue{}, int(unsafe.Sizeof(probeValue{})),
 			1, bpf.BPF_F_NO_PREALLOC, 0, bpf.ConvertKeyValue).WithCache()
-		_, err := m.OpenOrCreateUnpinned()
+		err := m.CreateUnpinned()
 		defer m.Close()
 		if err != nil {
 			return
diff --git a/pkg/rate/api_limiter.go b/pkg/rate/api_limiter.go
index 20e4284dba..85814a9e81 100644
--- a/pkg/rate/api_limiter.go
+++ b/pkg/rate/api_limiter.go
@@ -44,20 +44,27 @@ const (
 	// requirement is implemented
 	waitSemaphoreResolution = 10000000
 
-	logUUID                    = "uuid"
-	logAPICallName             = "name"
-	logProcessingDuration      = "processingDuration"
-	logParallelRequests        = "parallelRequests"
-	logMinWaitDuration         = "minWaitDuration"
-	logMaxWaitDuration         = "maxWaitDuration"
-	logMaxWaitDurationParallel = "maxWaitDurationParallel"
-	logWaitDurationLimit       = "waitDurationLimiter"
-	logWaitDurationTotal       = "waitDurationTotal"
-	logLimit                   = "limit"
-	logBurst                   = "burst"
-	logTotalDuration           = "totalDuration"
-	logError                   = "err"
-	logSkipped                 = "rateLimiterSkipped"
+	logUUID                   = "uuid"
+	logAPICallName            = "name"
+	logProcessingDuration     = "processingDuration"
+	logParallelRequests       = "parallelRequests"
+	logMinWaitDuration        = "minWaitDuration"
+	logMaxWaitDuration        = "maxWaitDuration"
+	logMaxWaitDurationLimiter = "maxWaitDurationLimiter"
+	logWaitDurationLimit      = "waitDurationLimiter"
+	logWaitDurationTotal      = "waitDurationTotal"
+	logLimit                  = "limit"
+	logBurst                  = "burst"
+	logTotalDuration          = "totalDuration"
+	logSkipped                = "rateLimiterSkipped"
+)
+
+type outcome string
+
+const (
+	outcomeParallelMaxWait outcome = "fail-parallel-wait"
+	outcomeLimitMaxWait    outcome = "fail-limit-wait"
+	outcomeReqCancelled            = "request-cancelled"
 )
 
 // APILimiter is an extension to x/time/rate.Limiter specifically for Cilium
@@ -415,7 +422,11 @@ func (l *APILimiter) requestFinished(r *limitedRequest, err error) {
 
 	r.finished = true
 
-	processingDuration := time.Since(r.startTime)
+	var processingDuration time.Duration
+	if !r.startTime.IsZero() {
+		processingDuration = time.Since(r.startTime)
+	}
+
 	totalDuration := time.Since(r.scheduleTime)
 
 	scopedLog := log.WithFields(logrus.Fields{
@@ -427,7 +438,7 @@ func (l *APILimiter) requestFinished(r *limitedRequest, err error) {
 	})
 
 	if err != nil {
-		scopedLog = scopedLog.WithField(logError, err)
+		scopedLog = scopedLog.WithError(err)
 	}
 
 	if l.params.Log {
@@ -442,30 +453,35 @@ func (l *APILimiter) requestFinished(r *limitedRequest, err error) {
 
 	l.mutex.Lock()
 
-	l.requestsProcessed++
-	l.currentRequestsInFlight--
-
-	l.processingDurations = append(l.processingDurations, processingDuration)
-	if exceed := len(l.processingDurations) - l.params.MeanOver; exceed > 0 {
-		l.processingDurations = l.processingDurations[exceed:]
+	if !r.startTime.IsZero() {
+		l.requestsProcessed++
+		l.currentRequestsInFlight--
 	}
-	l.meanProcessingDuration = calcMeanDuration(l.processingDurations)
 
-	l.waitDurations = append(l.waitDurations, r.waitDuration)
-	if exceed := len(l.waitDurations) - l.params.MeanOver; exceed > 0 {
-		l.waitDurations = l.waitDurations[exceed:]
-	}
-	l.meanWaitDuration = calcMeanDuration(l.waitDurations)
+	// Only auto-adjust ratelimiter using metrics from successful API requests
+	if err == nil {
+		l.processingDurations = append(l.processingDurations, processingDuration)
+		if exceed := len(l.processingDurations) - l.params.MeanOver; exceed > 0 {
+			l.processingDurations = l.processingDurations[exceed:]
+		}
+		l.meanProcessingDuration = calcMeanDuration(l.processingDurations)
 
-	if l.params.AutoAdjust && l.params.EstimatedProcessingDuration != 0 {
-		l.adjustmentFactor = l.calculateAdjustmentFactor()
-		l.parallelRequests = l.adjustedParallelRequests()
+		l.waitDurations = append(l.waitDurations, r.waitDuration)
+		if exceed := len(l.waitDurations) - l.params.MeanOver; exceed > 0 {
+			l.waitDurations = l.waitDurations[exceed:]
+		}
+		l.meanWaitDuration = calcMeanDuration(l.waitDurations)
 
-		if l.limiter != nil {
-			l.limiter.SetLimit(l.adjustedLimit())
+		if l.params.AutoAdjust && l.params.EstimatedProcessingDuration != 0 {
+			l.adjustmentFactor = l.calculateAdjustmentFactor()
+			l.parallelRequests = l.adjustedParallelRequests()
 
-			newBurst := l.adjustedBurst()
-			l.limiter.SetBurst(newBurst)
+			if l.limiter != nil {
+				l.limiter.SetLimit(l.adjustedLimit())
+
+				newBurst := l.adjustedBurst()
+				l.limiter.SetBurst(newBurst)
+			}
 		}
 	}
 
@@ -480,6 +496,7 @@ func (l *APILimiter) requestFinished(r *limitedRequest, err error) {
 		CurrentRequestsInFlight:     l.currentRequestsInFlight,
 		AdjustmentFactor:            l.adjustmentFactor,
 		Error:                       err,
+		Outcome:                     string(r.outcome),
 	}
 
 	if l.limiter != nil {
@@ -521,6 +538,7 @@ type limitedRequest struct {
 	waitSemaphoreWeight int64
 	uuid                string
 	finished            bool
+	outcome             outcome
 }
 
 // WaitDuration returns the duration the request had to wait
@@ -542,23 +560,34 @@ func (l *limitedRequest) Error(err error) {
 // configured MaxWaitDuration is exceeded, an error is returned. On success, a
 // LimitedRequest is returned on which Done() must be called when the API call
 // has completed or Error() if an error occurred.
-func (l *APILimiter) Wait(ctx context.Context) (req LimitedRequest, err error) {
+func (l *APILimiter) Wait(ctx context.Context) (LimitedRequest, error) {
+	req, err := l.wait(ctx)
+	if err != nil {
+		l.requestFinished(req, err)
+		return nil, err
+	}
+	return req, nil
+}
+
+func (l *APILimiter) wait(ctx context.Context) (req *limitedRequest, err error) {
 	var (
-		limitWaitDuration   time.Duration
-		waitDuration        time.Duration
-		waitSemaphoreWeight int64
-		uuid                = uuid.NewUUID().String()
-		scheduledAt         = time.Now()
-		r                   *rate.Reservation
+		limitWaitDuration time.Duration
+		r                 *rate.Reservation
 	)
 
+	req = &limitedRequest{
+		limiter:      l,
+		scheduleTime: time.Now(),
+		uuid:         uuid.NewUUID().String(),
+	}
+
 	l.mutex.Lock()
 
 	l.requestsScheduled++
 
 	scopedLog := log.WithFields(logrus.Fields{
 		logAPICallName:      l.name,
-		logUUID:             uuid,
+		logUUID:             req.uuid,
 		logParallelRequests: l.parallelRequests,
 	})
 
@@ -576,7 +605,9 @@ func (l *APILimiter) Wait(ctx context.Context) (req LimitedRequest, err error) {
 			scopedLog.Warning("Not processing API request due to cancelled context")
 		}
 		l.mutex.Unlock()
-		return nil, fmt.Errorf("request cancelled while waiting for rate limiting slot: %w", ctx.Err())
+		req.outcome = outcomeReqCancelled
+		err = fmt.Errorf("request cancelled while waiting for rate limiting slot: %w", ctx.Err())
+		return
 	default:
 	}
 
@@ -585,27 +616,8 @@ func (l *APILimiter) Wait(ctx context.Context) (req LimitedRequest, err error) {
 		scopedLog = scopedLog.WithField(logSkipped, skip)
 	}
 
-	if !skip && l.limiter != nil {
-		r = l.limiter.Reserve()
-		limitWaitDuration = r.Delay()
-
-		defer func() {
-			// In case the request is cancelled, also cancel the
-			// reservation so it does not impact the wait duration.
-			// The wait duration should only increase if requests
-			// are actually processed.
-			if err != nil && r != nil {
-				r.Cancel()
-			}
-		}()
-
-		scopedLog = scopedLog.WithFields(logrus.Fields{
-			logLimit:             fmt.Sprintf("%.2f/s", l.limiter.Limit()),
-			logBurst:             l.limiter.Burst(),
-			logWaitDurationLimit: limitWaitDuration,
-		})
-	}
 	parallelRequests := l.parallelRequests
+	meanProcessingDuration := l.meanProcessingDuration
 	l.mutex.Unlock()
 
 	if l.params.Log {
@@ -618,16 +630,69 @@ func (l *APILimiter) Wait(ctx context.Context) (req LimitedRequest, err error) {
 		goto skipRateLimiter
 	}
 
+	if parallelRequests > 0 {
+		waitCtx := ctx
+		if l.params.MaxWaitDuration > 0 {
+			ctx2, cancel := context.WithTimeout(ctx, l.params.MaxWaitDuration)
+			defer cancel()
+			waitCtx = ctx2
+		}
+		w := int64(waitSemaphoreResolution / parallelRequests)
+		err2 := l.parallelWaitSemaphore.Acquire(waitCtx, w)
+		if err2 != nil {
+			if l.params.Log {
+				scopedLog.WithError(err2).Warning("Not processing API request. Wait duration for maximum parallel requests exceeds maximum")
+			}
+			req.outcome = outcomeParallelMaxWait
+			err = fmt.Errorf("timed out while waiting to be served with %d parallel requests: %w", parallelRequests, err2)
+			return
+		}
+		req.waitSemaphoreWeight = w
+	}
+	req.waitDuration = time.Since(req.scheduleTime)
+
+	l.mutex.Lock()
+	if l.limiter != nil {
+		r = l.limiter.Reserve()
+		limitWaitDuration = r.Delay()
+
+		scopedLog = scopedLog.WithFields(logrus.Fields{
+			logLimit:                  fmt.Sprintf("%.2f/s", l.limiter.Limit()),
+			logBurst:                  l.limiter.Burst(),
+			logWaitDurationLimit:      limitWaitDuration,
+			logMaxWaitDurationLimiter: l.params.MaxWaitDuration - req.waitDuration,
+		})
+	}
+	l.mutex.Unlock()
+
 	if l.params.MinWaitDuration > 0 && limitWaitDuration < l.params.MinWaitDuration {
 		limitWaitDuration = l.params.MinWaitDuration
 	}
 
-	if (l.params.MaxWaitDuration > 0 && limitWaitDuration > l.params.MaxWaitDuration) || limitWaitDuration == rate.InfDuration {
+	if (l.params.MaxWaitDuration > 0 && (limitWaitDuration+req.waitDuration) > l.params.MaxWaitDuration) || limitWaitDuration == rate.InfDuration {
 		if l.params.Log {
 			scopedLog.Warning("Not processing API request. Wait duration exceeds maximum")
 		}
-		return nil, fmt.Errorf("request would have to wait %v to be served (maximum wait duration: %v)",
-			limitWaitDuration, l.params.MaxWaitDuration)
+
+		// The rate limiter should only consider a reservation valid if
+		// the request is actually processed. Cancellation of the
+		// reservation should happen before we sleep below.
+		if r != nil {
+			r.Cancel()
+		}
+
+		// Instead of returning immediately, pace the caller by
+		// sleeping for the mean processing duration. This helps
+		// against callers who disrespect 429 error codes and retry
+		// immediately.
+		if meanProcessingDuration > 0.0 {
+			time.Sleep(time.Duration(meanProcessingDuration * float64(time.Second)))
+		}
+
+		req.outcome = outcomeLimitMaxWait
+		err = fmt.Errorf("request would have to wait %v to be served (maximum wait duration: %v)",
+			limitWaitDuration, l.params.MaxWaitDuration-req.waitDuration)
+		return
 	}
 
 	if limitWaitDuration != 0 {
@@ -637,30 +702,19 @@ func (l *APILimiter) Wait(ctx context.Context) (req LimitedRequest, err error) {
 			if l.params.Log {
 				scopedLog.Warning("Not processing API request due to cancelled context while waiting")
 			}
-			return nil, fmt.Errorf("request cancelled while waiting for rate limiting slot: %w", ctx.Err())
-		}
-	}
-
-	if parallelRequests > 0 {
-		waitCtx := ctx
-		if l.params.MaxWaitDuration > 0 {
-			maxWaitDurationParallel := l.params.MaxWaitDuration - limitWaitDuration
-			scopedLog = scopedLog.WithField(logMaxWaitDurationParallel, maxWaitDurationParallel)
-			ctx2, cancel := context.WithTimeout(ctx, maxWaitDurationParallel)
-			defer cancel()
-			waitCtx = ctx2
-		}
-		waitSemaphoreWeight = int64(waitSemaphoreResolution / parallelRequests)
-		err := l.parallelWaitSemaphore.Acquire(waitCtx, waitSemaphoreWeight)
-		if err != nil {
-			if l.params.Log {
-				scopedLog.Warning("Not processing API request. Wait duration for maximum parallel requests exceeds maximum")
+			// The rate limiter should only consider a reservation
+			// valid if the request is actually processed.
+			if r != nil {
+				r.Cancel()
 			}
-			return nil, fmt.Errorf("timed out while waiting to be served with %d parallel requests: %w", parallelRequests, err)
+
+			req.outcome = outcomeReqCancelled
+			err = fmt.Errorf("request cancelled while waiting for rate limiting slot: %w", ctx.Err())
+			return
 		}
 	}
 
-	waitDuration = time.Since(scheduledAt)
+	req.waitDuration = time.Since(req.scheduleTime)
 
 skipRateLimiter:
 
@@ -668,26 +722,17 @@ skipRateLimiter:
 	l.currentRequestsInFlight++
 	l.mutex.Unlock()
 
-	log.WithFields(logrus.Fields{
-		logAPICallName:       l.name,
-		logUUID:              uuid,
-		logWaitDurationTotal: waitDuration,
-	}).Debug("API call is ready to be served")
+	scopedLog = scopedLog.WithField(logWaitDurationTotal, req.waitDuration)
 
 	if l.params.Log {
-		scopedLog.Info("Processing API request with rate limiter")
+		scopedLog.Info("API request released by rate limiter")
 	} else {
-		scopedLog.Debug("Processing API request with rate limiter")
+		scopedLog.Debug("API request released by rate limiter")
 	}
 
-	return &limitedRequest{
-		limiter:             l,
-		startTime:           time.Now(),
-		scheduleTime:        scheduledAt,
-		waitDuration:        waitDuration,
-		waitSemaphoreWeight: waitSemaphoreWeight,
-		uuid:                uuid,
-	}, nil
+	req.startTime = time.Now()
+	return req, nil
+
 }
 
 func parseRate(r string) (rate.Limit, error) {
@@ -732,6 +777,7 @@ type MetricsValues struct {
 	WaitDuration                time.Duration
 	MinWaitDuration             time.Duration
 	MaxWaitDuration             time.Duration
+	Outcome                     string
 	MeanProcessingDuration      float64
 	MeanWaitDuration            float64
 	EstimatedProcessingDuration float64
diff --git a/pkg/redirectpolicy/manager.go b/pkg/redirectpolicy/manager.go
index 6b1115cd2e..e47f433b3d 100644
--- a/pkg/redirectpolicy/manager.go
+++ b/pkg/redirectpolicy/manager.go
@@ -606,11 +606,11 @@ func (rpm *Manager) processConfigWithSinglePort(config *LRPConfig, pods ...*podM
 					},
 				}, pod.id,
 			}
-			if feM.feAddr.IP.To4() != nil {
+			if feM.feAddr.IP.To4() != nil && be.IP.To4() != nil {
 				if option.Config.EnableIPv4 {
 					bes4 = append(bes4, be)
 				}
-			} else {
+			} else if feM.feAddr.IP.To4() == nil && be.IP.To4() == nil {
 				if option.Config.EnableIPv6 {
 					bes6 = append(bes6, be)
 				}
@@ -667,11 +667,11 @@ func (rpm *Manager) processConfigWithNamedPorts(config *LRPConfig, pods ...*podM
 						},
 						pod.id,
 					}
-					if feM.feAddr.IP.To4() != nil {
+					if feM.feAddr.IP.To4() != nil && be.IP.To4() != nil {
 						if option.Config.EnableIPv4 {
 							bes4 = append(bes4, be)
 						}
-					} else {
+					} else if feM.feAddr.IP.To4() == nil && be.IP.To4() == nil {
 						if option.Config.EnableIPv6 {
 							bes6 = append(bes6, be)
 						}
diff --git a/pkg/service/service.go b/pkg/service/service.go
index 3a5bd8cbfd..3f914b282d 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -44,7 +44,7 @@ var (
 type LBMap interface {
 	UpsertService(*lbmap.UpsertServiceParams) error
 	DeleteService(lb.L3n4AddrID, int, bool) error
-	AddBackend(uint16, net.IP, uint16, bool) error
+	AddBackend(uint16, net.IP, lb.L4Type, uint16, bool) error
 	DeleteBackendByID(uint16, bool) error
 	AddAffinityMatch(uint16, uint16) error
 	DeleteAffinityMatch(uint16, uint16) error
@@ -684,6 +684,7 @@ func (s *Service) upsertServiceIntoLBMaps(svc *svcInfo, onlyLocalBackends bool,
 		}).Debug("Adding new backend")
 
 		if err := s.lbmap.AddBackend(uint16(b.ID), b.L3n4Addr.IP,
+			b.L3n4Addr.L4Addr.Protocol,
 			b.L3n4Addr.L4Addr.Port, ipv6); err != nil {
 			return err
 		}
@@ -699,6 +700,7 @@ func (s *Service) upsertServiceIntoLBMaps(svc *svcInfo, onlyLocalBackends bool,
 		ID:                        uint16(svc.frontend.ID),
 		IP:                        svc.frontend.L3n4Addr.IP,
 		Port:                      svc.frontend.L3n4Addr.L4Addr.Port,
+		Protocol:                  string(svc.frontend.L3n4Addr.L4Addr.Protocol),
 		Backends:                  backends,
 		PrevBackendCount:          prevBackendCount,
 		IPv6:                      ipv6,
diff --git a/pkg/u8proto/u8proto.go b/pkg/u8proto/u8proto.go
index b396d2c043..91f26a07eb 100644
--- a/pkg/u8proto/u8proto.go
+++ b/pkg/u8proto/u8proto.go
@@ -43,6 +43,7 @@ var protoNames = map[U8proto]string{
 var ProtoIDs = map[string]U8proto{
 	"all":    0,
 	"any":    0,
+	"none":   0,
 	"icmp":   1,
 	"tcp":    6,
 	"udp":    17,
@@ -62,5 +63,13 @@ func ParseProtocol(proto string) (U8proto, error) {
 	if u, ok := ProtoIDs[strings.ToLower(proto)]; ok {
 		return u, nil
 	}
-	return 0, fmt.Errorf("unknown protocol '%s'", proto)
+	return 0, fmt.Errorf("unknown protocol %q", proto)
+}
+
+func FromNumber(proto uint8) (U8proto, error) {
+	_, ok := protoNames[U8proto(proto)]
+	if !ok {
+		return 0, fmt.Errorf("unknown protocol %d", proto)
+	}
+	return U8proto(proto), nil
 }
diff --git a/vendor/github.com/cilium/arping/README.md b/vendor/github.com/cilium/arping/README.md
index bdb91d46be..086ade5b74 100644
--- a/vendor/github.com/cilium/arping/README.md
+++ b/vendor/github.com/cilium/arping/README.md
@@ -1,3 +1,5 @@
+[![pkg.go.dev](https://godoc.org/github.com/j-keck/arping?status.svg)](https://pkg.go.dev/github.com/j-keck/arping)
+
 # arping
   
 arping is a native go library to ping a host per arp datagram, or query a host mac address 
diff --git a/vendor/github.com/cilium/arping/arping.go b/vendor/github.com/cilium/arping/arping.go
index 87b84f004b..c9a57576dd 100644
--- a/vendor/github.com/cilium/arping/arping.go
+++ b/vendor/github.com/cilium/arping/arping.go
@@ -59,6 +59,7 @@
 package arping
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"io/ioutil"
@@ -73,7 +74,7 @@ var (
 	ErrTimeout = errors.New("timeout")
 
 	verboseLog = log.New(ioutil.Discard, "", 0)
-	timeout    = time.Duration(500 * time.Millisecond)
+	timeout    = 1 * time.Second
 )
 
 // Ping sends an arp ping to 'dstIP'
@@ -117,10 +118,11 @@ func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Du
 	broadcastMac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
 	request := newArpRequest(srcMac, srcIP, broadcastMac, dstIP)
 
-	if err := initialize(iface); err != nil {
+	req, err := initialize(iface)
+	if err != nil {
 		return nil, 0, err
 	}
-	defer deinitialize()
+	defer req.deinitialize()
 
 	type PingResult struct {
 		mac      net.HardwareAddr
@@ -129,39 +131,52 @@ func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Du
 	}
 	pingResultChan := make(chan PingResult)
 
+	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+	defer cancel()
+
 	go func() {
 		// send arp request
 		verboseLog.Printf("arping '%s' over interface: '%s' with address: '%s'\n", dstIP, iface.Name, srcIP)
-		if sendTime, err := send(request); err != nil {
-			pingResultChan <- PingResult{nil, 0, err}
-		} else {
-			for {
-				// receive arp response
-				response, receiveTime, err := receive()
-
-				if err != nil {
-					pingResultChan <- PingResult{nil, 0, err}
-					return
-				}
-
-				if response.IsResponseOf(request) {
-					duration := receiveTime.Sub(sendTime)
-					verboseLog.Printf("process received arp: srcIP: '%s', srcMac: '%s'\n",
-						response.SenderIP(), response.SenderMac())
-					pingResultChan <- PingResult{response.SenderMac(), duration, err}
-					return
+		sendTime, err := req.send(request)
+		if err != nil {
+			select {
+			case pingResultChan <- PingResult{nil, 0, err}:
+			case <-ctx.Done():
+			}
+			return
+		}
+		for {
+			// receive arp response
+			response, receiveTime, err := req.receive()
+
+			if err != nil {
+				select {
+				case pingResultChan <- PingResult{nil, 0, err}:
+				case <-ctx.Done():
 				}
+				return
+			}
 
-				verboseLog.Printf("ignore received arp: srcIP: '%s', srcMac: '%s'\n",
+			if response.IsResponseOf(request) {
+				duration := receiveTime.Sub(sendTime)
+				verboseLog.Printf("process received arp: srcIP: '%s', srcMac: '%s'\n",
 					response.SenderIP(), response.SenderMac())
+				select {
+				case pingResultChan <- PingResult{response.SenderMac(), duration, err}:
+				case <-ctx.Done():
+				}
+				return
 			}
+
+			verboseLog.Printf("ignore received arp: srcIP: '%s', srcMac: '%s'\n",
+				response.SenderIP(), response.SenderMac())
 		}
 	}()
 
 	select {
 	case pingResult := <-pingResultChan:
 		return pingResult.mac, pingResult.duration, pingResult.err
-	case <-time.After(timeout):
+	case <-ctx.Done():
 		return nil, 0, ErrTimeout
 	}
 }
@@ -202,12 +217,13 @@ func GratuitousArpOverIface(srcIP net.IP, iface net.Interface) error {
 	broadcastMac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
 	request := newArpRequest(srcMac, srcIP, broadcastMac, srcIP)
 
-	if err := initialize(iface); err != nil {
+	req, err := initialize(iface)
+	if err != nil {
 		return err
 	}
-	defer deinitialize()
+	defer req.deinitialize()
 	verboseLog.Printf("gratuitous arp over interface: '%s' with address: '%s'\n", iface.Name, srcIP)
-	_, err := send(request)
+	_, err = req.send(request)
 	return err
 }
 
diff --git a/vendor/github.com/cilium/arping/arping_linux.go b/vendor/github.com/cilium/arping/arping_linux.go
index 6e2adfb2c0..21241555b9 100644
--- a/vendor/github.com/cilium/arping/arping_linux.go
+++ b/vendor/github.com/cilium/arping/arping_linux.go
@@ -6,26 +6,34 @@ import (
 	"time"
 )
 
-var sock int
-var toSockaddr syscall.SockaddrLinklayer
+type requester struct {
+	sock       int
+	toSockaddr syscall.SockaddrLinklayer
+}
 
-func initialize(iface net.Interface) error {
-	toSockaddr = syscall.SockaddrLinklayer{Ifindex: iface.Index}
+func initialize(iface net.Interface) (*requester, error) {
+	toSockaddr := syscall.SockaddrLinklayer{Ifindex: iface.Index}
 
 	// 1544 = htons(ETH_P_ARP)
 	const proto = 1544
-	var err error
-	sock, err = syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, proto)
-	return err
+	sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, proto)
+	if err != nil {
+		return nil, err
+	}
+
+	return &requester{
+		sock:       sock,
+		toSockaddr: toSockaddr,
+	}, nil
 }
 
-func send(request arpDatagram) (time.Time, error) {
-	return time.Now(), syscall.Sendto(sock, request.MarshalWithEthernetHeader(), 0, &toSockaddr)
+func (r *requester) send(request arpDatagram) (time.Time, error) {
+	return time.Now(), syscall.Sendto(r.sock, request.MarshalWithEthernetHeader(), 0, &r.toSockaddr)
 }
 
-func receive() (arpDatagram, time.Time, error) {
+func (r *requester) receive() (arpDatagram, time.Time, error) {
 	buffer := make([]byte, 128)
-	n, _, err := syscall.Recvfrom(sock, buffer, 0)
+	n, _, err := syscall.Recvfrom(r.sock, buffer, 0)
 	if err != nil {
 		return arpDatagram{}, time.Now(), err
 	}
@@ -33,6 +41,6 @@ func receive() (arpDatagram, time.Time, error) {
 	return parseArpDatagram(buffer[14:n]), time.Now(), nil
 }
 
-func deinitialize() error {
-	return syscall.Close(sock)
+func (r *requester) deinitialize() error {
+	return syscall.Close(r.sock)
 }
diff --git a/vendor/github.com/cilium/arping/go.mod b/vendor/github.com/cilium/arping/go.mod
index 62ff89b8a7..c33600d090 100644
--- a/vendor/github.com/cilium/arping/go.mod
+++ b/vendor/github.com/cilium/arping/go.mod
@@ -1,1 +1,3 @@
 module github.com/cilium/arping
+
+go 1.15
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 6876b86880..ef8800f641 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -84,7 +84,7 @@ github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1
 github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1
 # github.com/cespare/xxhash/v2 v2.1.1
 github.com/cespare/xxhash/v2
-# github.com/cilium/arping v1.0.1-0.20190728065459-c5eaf8d7a710
+# github.com/cilium/arping v1.0.1-0.20201009104213-b546132ab753
 ## explicit
 github.com/cilium/arping
 # github.com/cilium/deepequal-gen v0.0.0-20200406125435-ad6a9003139e


Test patch:
diff --git a/pkg/bpf/map_linux_test.go b/pkg/bpf/map_linux_test.go
index e81f3b199c..a205e81d96 100644
--- a/pkg/bpf/map_linux_test.go
+++ b/pkg/bpf/map_linux_test.go
@@ -598,3 +598,31 @@ func (s *BPFPrivilegedTestSuite) TestUnpin(c *C) {
 	c.Assert(err, IsNil)
 	c.Assert(exist, Equals, false)
 }
+
+func (s *BPFPrivilegedTestSuite) TestCreateUnpinned(c *C) {
+	m := NewMap("cilium_test_create_unpinned",
+		MapTypeHash,
+		&TestKey{},
+		int(unsafe.Sizeof(TestKey{})),
+		&TestValue{},
+		int(unsafe.Sizeof(TestValue{})),
+		maxEntries,
+		BPF_F_NO_PREALLOC,
+		0,
+		ConvertKeyValue).WithCache()
+	err := m.CreateUnpinned()
+	c.Assert(err, IsNil)
+	exist, err := m.exist()
+	c.Assert(err, IsNil)
+	c.Assert(exist, Equals, false)
+
+	key1 := &TestKey{Key: 105}
+	value1 := &TestValue{Value: 205}
+	err = m.Update(key1, value1)
+	c.Assert(err, IsNil)
+
+	var value2 TestValue
+	err = LookupElement(m.fd, unsafe.Pointer(key1), unsafe.Pointer(&value2))
+	c.Assert(err, IsNil)
+	c.Assert(*value1, Equals, value2)
+}
diff --git a/pkg/comparator/comparator_test.go b/pkg/comparator/comparator_test.go
index cd940ade17..2e08ab034b 100644
--- a/pkg/comparator/comparator_test.go
+++ b/pkg/comparator/comparator_test.go
@@ -152,3 +152,116 @@ func (s *ComparatorSuite) TestMapBoolEquals(c *C) {
 		c.Assert(MapBoolEquals(tt.m1, tt.m2), Equals, tt.want)
 	}
 }
+
+func (s *ComparatorSuite) TestMapStringEqualsIgnoreKeys(c *C) {
+	tests := []struct {
+		name         string
+		m1           map[string]string
+		m2           map[string]string
+		keysToIgnore []string
+		want         bool
+	}{
+		{
+			name: "test-1",
+			m1:   nil,
+			m2:   nil,
+			want: true,
+		},
+		{
+			m1: map[string]string{
+				"foo": "bar",
+			},
+			m2: map[string]string{
+				"foo": "bar",
+			},
+			want: true,
+		},
+		{
+			name: "test-2",
+			m1:   map[string]string{},
+			m2:   map[string]string{},
+			want: true,
+		},
+		{
+			name: "test-3",
+			m1: map[string]string{
+				"fo": "bar",
+			},
+			m2: map[string]string{
+				"foo": "bar",
+			},
+			want: false,
+		},
+		{
+			name: "test-4",
+			m1:   nil,
+			m2: map[string]string{
+				"foo": "bar",
+			},
+			want: false,
+		},
+		{
+			name: "test-5",
+			m1: map[string]string{
+				"foo": "bar",
+			},
+			m2:   nil,
+			want: false,
+		},
+		{
+			name: "test-6",
+			m1: map[string]string{
+				"foo": "bar",
+			},
+			m2:   nil,
+			want: false,
+		},
+		{
+			name: "test-7",
+			m1: map[string]string{
+				"foo": "bar",
+			},
+			m2:           nil,
+			keysToIgnore: []string{"foo"},
+			// Although we are ignoring "foo", m2 is nil.
+			want: false,
+		},
+		{
+			name: "test-8",
+			m1: map[string]string{
+				"foo": "bar",
+			},
+			m2:           map[string]string{},
+			keysToIgnore: []string{"foo"},
+			want:         true,
+		},
+		{
+			name: "test-9",
+			m1:   map[string]string{},
+			m2: map[string]string{
+				"foo": "bar",
+			},
+			keysToIgnore: []string{"foo"},
+			want:         true,
+		},
+		{
+			name:         "test-10",
+			m1:           map[string]string{},
+			m2:           map[string]string{},
+			keysToIgnore: []string{"foo"},
+			want:         true,
+		},
+		{
+			name: "test-10",
+			m1:   nil,
+			m2: map[string]string{
+				"foo": "bar",
+			},
+			keysToIgnore: []string{"foo"},
+			want:         false,
+		},
+	}
+	for _, tt := range tests {
+		c.Assert(MapStringEqualsIgnoreKeys(tt.m1, tt.m2, tt.keysToIgnore), Equals, tt.want, Commentf("%s", tt.name))
+	}
+}
diff --git a/pkg/hubble/parser/threefour/parser_test.go b/pkg/hubble/parser/threefour/parser_test.go
index 006957d458..c8b5c568a8 100644
--- a/pkg/hubble/parser/threefour/parser_test.go
+++ b/pkg/hubble/parser/threefour/parser_test.go
@@ -384,6 +384,7 @@ func TestDecodePolicyVerdictNotify(t *testing.T) {
 	assert.Equal(t, int32(api.MessageTypePolicyVerdict), f.GetEventType().GetType())
 	assert.Equal(t, flowpb.TrafficDirection_INGRESS, f.GetTrafficDirection())
 	assert.Equal(t, uint32(151), f.GetDropReason())
+	assert.Equal(t, flowpb.DropReason(151), f.GetDropReasonDesc())
 	assert.Equal(t, flowpb.Verdict_DROPPED, f.GetVerdict())
 	assert.Equal(t, []string{"dst=label"}, f.GetSource().GetLabels())
 }
@@ -405,6 +406,7 @@ func TestDecodeDropReason(t *testing.T) {
 	require.NoError(t, err)
 
 	assert.Equal(t, uint32(reason), f.GetDropReason())
+	assert.Equal(t, flowpb.DropReason(reason), f.GetDropReasonDesc())
 }
 
 func TestDecodeLocalIdentity(t *testing.T) {
diff --git a/pkg/hubble/testutils/fake.go b/pkg/hubble/testutils/fake.go
index 95dc2ee030..b3dc53cf66 100644
--- a/pkg/hubble/testutils/fake.go
+++ b/pkg/hubble/testutils/fake.go
@@ -375,6 +375,7 @@ type FakeFlow struct {
 	DestinationService *flowpb.Service
 	TrafficDirection   flowpb.TrafficDirection
 	PolicyMatchType    uint32
+	DropReasonDesc     flowpb.DropReason
 }
 
 // Reset implements flowpb.Message for the FakeFlow.
@@ -481,6 +482,11 @@ func (f *FakeFlow) GetPolicyMatchType() uint32 {
 	return f.PolicyMatchType
 }
 
+// GetDropReasonDesc implements v1.Flow for the FakeFlow.
+func (f *FakeFlow) GetDropReasonDesc() flowpb.DropReason {
+	return f.DropReasonDesc
+}
+
 // GetSummary implements v1.Flow for the FakeFlow.
 func (f *FakeFlow) GetSummary() string {
 	return "deprecated"
diff --git a/pkg/k8s/endpoints_test.go b/pkg/k8s/endpoints_test.go
index 7bc606ef5a..0e3ebdca18 100644
--- a/pkg/k8s/endpoints_test.go
+++ b/pkg/k8s/endpoints_test.go
@@ -52,7 +52,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -67,7 +67,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -86,7 +86,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -100,7 +100,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.2": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -118,7 +118,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -132,7 +132,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foz": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -150,7 +150,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -158,6 +158,70 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 					},
 				},
 			},
+			args: args{
+				o: &Endpoints{
+					Backends: map[string]*Backend{
+						"172.20.0.1": {
+							Ports: map[string]*loadbalancer.L4Addr{
+								"foo": {
+									Protocol: loadbalancer.TCP,
+									Port:     2,
+								},
+							},
+						},
+					},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "protocols different content",
+			fields: fields{
+				svcEP: &Endpoints{
+					Backends: map[string]*Backend{
+						"172.20.0.1": {
+							Ports: map[string]*loadbalancer.L4Addr{
+								"foo": {
+									Protocol: loadbalancer.TCP,
+									Port:     2,
+								},
+							},
+						},
+					},
+				},
+			},
+			args: args{
+				o: &Endpoints{
+					Backends: map[string]*Backend{
+						"172.20.0.1": {
+							Ports: map[string]*loadbalancer.L4Addr{
+								"foo": {
+									Protocol: loadbalancer.UDP,
+									Port:     2,
+								},
+							},
+						},
+					},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "protocols different one none",
+			fields: fields{
+				svcEP: &Endpoints{
+					Backends: map[string]*Backend{
+						"172.20.0.1": {
+							Ports: map[string]*loadbalancer.L4Addr{
+								"foo": {
+									Protocol: loadbalancer.TCP,
+									Port:     2,
+								},
+							},
+						},
+					},
+				},
+			},
 			args: args{
 				o: &Endpoints{
 					Backends: map[string]*Backend{
@@ -182,7 +246,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
@@ -196,11 +260,11 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 								"baz": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     2,
 								},
 							},
@@ -219,7 +283,7 @@ func TestEndpoints_DeepEqual(t *testing.T) {
 						"172.20.0.1": {
 							Ports: map[string]*loadbalancer.L4Addr{
 								"foo": {
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     1,
 								},
 							},
diff --git a/pkg/k8s/service_cache_test.go b/pkg/k8s/service_cache_test.go
index 332248dbdd..531fc96ce9 100644
--- a/pkg/k8s/service_cache_test.go
+++ b/pkg/k8s/service_cache_test.go
@@ -95,33 +95,6 @@ func (s *K8sSuite) TestGetUniqueServiceFrontends(c *check.C) {
 		"1.1.1.1:20/TCP": {},
 		"2.2.2.2:20/UDP": {},
 	})
-
-	scopes := []uint8{loadbalancer.ScopeExternal, loadbalancer.ScopeInternal}
-	for _, scope := range scopes {
-		// Validate all frontends as exact matches
-		// These should match only for external scope
-		exact_match_ok := scope == loadbalancer.ScopeExternal
-		frontend := loadbalancer.NewL3n4Addr(loadbalancer.TCP, net.ParseIP("1.1.1.1"), 10, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, exact_match_ok)
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.TCP, net.ParseIP("1.1.1.1"), 20, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, exact_match_ok)
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.UDP, net.ParseIP("2.2.2.2"), 20, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, exact_match_ok)
-
-		// Validate protocol mismatch on exact match
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.TCP, net.ParseIP("2.2.2.2"), 20, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, false)
-
-		// Validate protocol wildcard matching
-		// These should match only for external scope
-		wild_match_ok := scope == loadbalancer.ScopeExternal
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.NONE, net.ParseIP("2.2.2.2"), 20, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, wild_match_ok)
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.NONE, net.ParseIP("1.1.1.1"), 10, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, wild_match_ok)
-		frontend = loadbalancer.NewL3n4Addr(loadbalancer.NONE, net.ParseIP("1.1.1.1"), 20, scope)
-		c.Assert(frontends.LooseMatch(*frontend), check.Equals, wild_match_ok)
-	}
 }
 
 func (s *K8sSuite) TestServiceCacheEndpoints(c *check.C) {
diff --git a/pkg/k8s/service_test.go b/pkg/k8s/service_test.go
index 6484c5aed9..0c59d9078c 100644
--- a/pkg/k8s/service_test.go
+++ b/pkg/k8s/service_test.go
@@ -180,41 +180,6 @@ func (s *K8sSuite) TestIsK8ServiceExternal(c *check.C) {
 	c.Assert(si.IsExternal(), check.Equals, false)
 }
 
-func (s *K8sSuite) TestServiceUniquePorts(c *check.C) {
-	type testMatrix struct {
-		input    Service
-		expected map[uint16]bool
-	}
-
-	matrix := []testMatrix{
-		{
-			input:    Service{},
-			expected: map[uint16]bool{},
-		},
-		{
-			input: Service{
-				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
-					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
-						Port:     1,
-					},
-					loadbalancer.FEPortName("bar"): {
-						Protocol: loadbalancer.NONE,
-						Port:     2,
-					},
-				},
-			},
-			expected: map[uint16]bool{
-				1: true,
-				2: true,
-			}},
-	}
-
-	for _, m := range matrix {
-		c.Assert(m.input.UniquePorts(), checker.DeepEquals, m.expected)
-	}
-}
-
 func TestService_Equals(t *testing.T) {
 	type args struct {
 		o *Service
@@ -232,7 +197,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -241,7 +206,7 @@ func TestService_Equals(t *testing.T) {
 						"0.0.0.0:31000": {
 							L3n4Addr: loadbalancer.L3n4Addr{
 								L4Addr: loadbalancer.L4Addr{
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     31000,
 								},
 								IP: net.IPv4(0, 0, 0, 0),
@@ -264,7 +229,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -273,7 +238,7 @@ func TestService_Equals(t *testing.T) {
 							"0.0.0.0:31000": {
 								L3n4Addr: loadbalancer.L3n4Addr{
 									L4Addr: loadbalancer.L4Addr{
-										Protocol: loadbalancer.NONE,
+										Protocol: loadbalancer.TCP,
 										Port:     31000,
 									},
 									IP: net.IPv4(0, 0, 0, 0),
@@ -300,7 +265,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -315,7 +280,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -336,7 +301,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -349,7 +314,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -368,7 +333,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foz"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -381,7 +346,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -398,13 +363,73 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
 				Labels:   map[string]string{},
 				Selector: map[string]string{},
 			},
+			args: args{
+				o: &Service{
+					FrontendIP: net.ParseIP("1.1.1.1"),
+					IsHeadless: true,
+					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
+						loadbalancer.FEPortName("foo"): {
+							Protocol: loadbalancer.TCP,
+							Port:     2,
+						},
+					},
+					Labels:   map[string]string{},
+					Selector: map[string]string{},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "protocols different content",
+			fields: &Service{
+				FrontendIP: net.ParseIP("1.1.1.1"),
+				IsHeadless: true,
+				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
+					loadbalancer.FEPortName("foo"): {
+						Protocol: loadbalancer.TCP,
+						Port:     2,
+					},
+				},
+				Labels:   map[string]string{},
+				Selector: map[string]string{},
+			},
+			args: args{
+				o: &Service{
+					FrontendIP: net.ParseIP("1.1.1.1"),
+					IsHeadless: true,
+					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
+						loadbalancer.FEPortName("foo"): {
+							Protocol: loadbalancer.UDP,
+							Port:     2,
+						},
+					},
+					Labels:   map[string]string{},
+					Selector: map[string]string{},
+				},
+			},
+			want: false,
+		},
+		{
+			name: "protocols different content one is none",
+			fields: &Service{
+				FrontendIP: net.ParseIP("1.1.1.1"),
+				IsHeadless: true,
+				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
+					loadbalancer.FEPortName("foo"): {
+						Protocol: loadbalancer.TCP,
+						Port:     2,
+					},
+				},
+				Labels:   map[string]string{},
+				Selector: map[string]string{},
+			},
 			args: args{
 				o: &Service{
 					FrontendIP: net.ParseIP("1.1.1.1"),
@@ -428,7 +453,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -441,11 +466,11 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 						loadbalancer.FEPortName("baz"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     2,
 						},
 					},
@@ -469,7 +494,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -486,7 +511,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: true,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -495,7 +520,7 @@ func TestService_Equals(t *testing.T) {
 						"1.1.1.1:31000": {
 							L3n4Addr: loadbalancer.L3n4Addr{
 								L4Addr: loadbalancer.L4Addr{
-									Protocol: loadbalancer.NONE,
+									Protocol: loadbalancer.TCP,
 									Port:     31000,
 								},
 								IP: net.IPv4(1, 1, 1, 1),
@@ -518,7 +543,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: true,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
@@ -527,7 +552,7 @@ func TestService_Equals(t *testing.T) {
 							"0.0.0.0:31000": {
 								L3n4Addr: loadbalancer.L3n4Addr{
 									L4Addr: loadbalancer.L4Addr{
-										Protocol: loadbalancer.NONE,
+										Protocol: loadbalancer.TCP,
 										Port:     31000,
 									},
 									IP: net.IPv4(0, 0, 0, 0),
@@ -554,7 +579,7 @@ func TestService_Equals(t *testing.T) {
 				IsHeadless: false,
 				Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 					loadbalancer.FEPortName("foo"): {
-						Protocol: loadbalancer.NONE,
+						Protocol: loadbalancer.TCP,
 						Port:     1,
 					},
 				},
@@ -572,7 +597,7 @@ func TestService_Equals(t *testing.T) {
 					IsHeadless: false,
 					Ports: map[loadbalancer.FEPortName]*loadbalancer.L4Addr{
 						loadbalancer.FEPortName("foo"): {
-							Protocol: loadbalancer.NONE,
+							Protocol: loadbalancer.TCP,
 							Port:     1,
 						},
 					},
diff --git a/pkg/loadbalancer/loadbalancer_test.go b/pkg/loadbalancer/loadbalancer_test.go
index 64a5685e79..336e316bbf 100644
--- a/pkg/loadbalancer/loadbalancer_test.go
+++ b/pkg/loadbalancer/loadbalancer_test.go
@@ -45,12 +45,12 @@ func TestL4Addr_Equals(t *testing.T) {
 		{
 			name: "both equal",
 			fields: &L4Addr{
-				Protocol: NONE,
+				Protocol: TCP,
 				Port:     1,
 			},
 			args: args{
 				o: &L4Addr{
-					Protocol: NONE,
+					Protocol: TCP,
 					Port:     1,
 				},
 			},
@@ -59,12 +59,12 @@ func TestL4Addr_Equals(t *testing.T) {
 		{
 			name: "both different",
 			fields: &L4Addr{
-				Protocol: NONE,
+				Protocol: TCP,
 				Port:     0,
 			},
 			args: args{
 				o: &L4Addr{
-					Protocol: NONE,
+					Protocol: TCP,
 					Port:     1,
 				},
 			},
@@ -78,12 +78,40 @@ func TestL4Addr_Equals(t *testing.T) {
 		{
 			name: "other nil",
 			fields: &L4Addr{
-				Protocol: NONE,
+				Protocol: TCP,
 				Port:     1,
 			},
 			args: args{},
 			want: false,
 		},
+		{
+			name: "protocol different",
+			fields: &L4Addr{
+				Protocol: TCP,
+				Port:     1,
+			},
+			args: args{
+				o: &L4Addr{
+					Protocol: UDP,
+					Port:     1,
+				},
+			},
+			want: false,
+		},
+		{
+			name: "protocol different one is none",
+			fields: &L4Addr{
+				Protocol: TCP,
+				Port:     1,
+			},
+			args: args{
+				o: &L4Addr{
+					Protocol: NONE,
+					Port:     1,
+				},
+			},
+			want: false,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -110,7 +138,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 			fields: &L3n4AddrID{
 				L3n4Addr: L3n4Addr{
 					L4Addr: L4Addr{
-						Protocol: NONE,
+						Protocol: TCP,
 						Port:     1,
 					},
 					IP: net.IPv4(1, 1, 1, 1),
@@ -121,7 +149,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 				o: &L3n4AddrID{
 					L3n4Addr: L3n4Addr{
 						L4Addr: L4Addr{
-							Protocol: NONE,
+							Protocol: TCP,
 							Port:     1,
 						},
 						IP: net.IPv4(1, 1, 1, 1),
@@ -136,7 +164,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 			fields: &L3n4AddrID{
 				L3n4Addr: L3n4Addr{
 					L4Addr: L4Addr{
-						Protocol: NONE,
+						Protocol: TCP,
 						Port:     1,
 					},
 					IP: net.IPv4(1, 1, 1, 1),
@@ -147,7 +175,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 				o: &L3n4AddrID{
 					L3n4Addr: L3n4Addr{
 						L4Addr: L4Addr{
-							Protocol: NONE,
+							Protocol: TCP,
 							Port:     1,
 						},
 						IP: net.IPv4(1, 1, 1, 1),
@@ -162,7 +190,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 			fields: &L3n4AddrID{
 				L3n4Addr: L3n4Addr{
 					L4Addr: L4Addr{
-						Protocol: NONE,
+						Protocol: TCP,
 						Port:     1,
 					},
 					IP: net.IPv4(2, 2, 2, 2),
@@ -173,7 +201,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 				o: &L3n4AddrID{
 					L3n4Addr: L3n4Addr{
 						L4Addr: L4Addr{
-							Protocol: NONE,
+							Protocol: TCP,
 							Port:     1,
 						},
 						IP: net.IPv4(1, 1, 1, 1),
@@ -188,7 +216,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 			fields: &L3n4AddrID{
 				L3n4Addr: L3n4Addr{
 					L4Addr: L4Addr{
-						Protocol: NONE,
+						Protocol: TCP,
 						Port:     2,
 					},
 					IP: net.IPv4(1, 1, 1, 1),
@@ -199,7 +227,7 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 				o: &L3n4AddrID{
 					L3n4Addr: L3n4Addr{
 						L4Addr: L4Addr{
-							Protocol: NONE,
+							Protocol: TCP,
 							Port:     1,
 						},
 						IP: net.IPv4(1, 1, 1, 1),
@@ -209,6 +237,32 @@ func TestL3n4AddrID_Equals(t *testing.T) {
 			},
 			want: false,
 		},
+		{
+			name: "protocols different",
+			fields: &L3n4AddrID{
+				L3n4Addr: L3n4Addr{
+					L4Addr: L4Addr{
+						Protocol: TCP,
+						Port:     2,
+					},
+					IP: net.IPv4(1, 1, 1, 1),
+				},
+				ID: 1,
+			},
+			args: args{
+				o: &L3n4AddrID{
+					L3n4Addr: L3n4Addr{
+						L4Addr: L4Addr{
+							Protocol: UDP,
+							Port:     2,
+						},
+						IP: net.IPv4(1, 1, 1, 1),
+					},
+					ID: 1,
+				},
+			},
+			want: false,
+		},
 		{
 			name: "both nil",
 			args: args{},
diff --git a/pkg/policy/portmap_test.go b/pkg/policy/portmap_test.go
index d5091772a0..662caa345a 100644
--- a/pkg/policy/portmap_test.go
+++ b/pkg/policy/portmap_test.go
@@ -56,7 +56,7 @@ func (ds *PolicyTestSuite) TestPolicyNewPortProto(c *C) {
 
 	_, err = newPortProto(80, "cccp")
 	c.Assert(err, Not(IsNil))
-	c.Assert(err.Error(), Equals, "unknown protocol 'cccp'")
+	c.Assert(err.Error(), Equals, "unknown protocol \"cccp\"")
 
 	np, err = newPortProto(88, "")
 	c.Assert(err, IsNil)
diff --git a/pkg/rate/api_limiter_test.go b/pkg/rate/api_limiter_test.go
index f9c0e91d37..e649b3dd15 100644
--- a/pkg/rate/api_limiter_test.go
+++ b/pkg/rate/api_limiter_test.go
@@ -19,11 +19,13 @@ package rate
 import (
 	"context"
 	"fmt"
+	"sync/atomic"
 	"time"
 
 	"github.com/cilium/cilium/pkg/lock"
 	"github.com/cilium/cilium/pkg/testutils"
 
+	"golang.org/x/sync/semaphore"
 	"golang.org/x/time/rate"
 	"gopkg.in/check.v1"
 )
@@ -716,3 +718,91 @@ func (b *ControllerSuite) TestAdjustedParallelRequests(c *check.C) {
 	a.adjustmentFactor = 1.0
 	c.Assert(a.adjustedParallelRequests(), check.Equals, 2)
 }
+
+func (b *ControllerSuite) TestStressRateLimiter(c *check.C) {
+	a := NewAPILimiter("foo", APILimiterParameters{
+		EstimatedProcessingDuration: 5 * time.Millisecond,
+		RateLimit:                   1000.0,
+		ParallelRequests:            50,
+		RateBurst:                   1,
+		MaxWaitDuration:             10 * time.Millisecond,
+		AutoAdjust:                  true,
+	}, nil)
+
+	var (
+		sem                = semaphore.NewWeighted(100)
+		completed, retries int32
+	)
+
+	go func() {
+		for i := 0; i < 1000; i++ {
+			sem.Acquire(context.Background(), 1)
+			go func() {
+				var (
+					err error
+					req LimitedRequest
+				)
+				for req == nil {
+					req, err = a.Wait(context.Background())
+					if err == nil {
+						time.Sleep(5 * time.Millisecond)
+						req.Done()
+						atomic.AddInt32(&completed, 1)
+						sem.Release(1)
+						return
+					}
+					atomic.AddInt32(&retries, 1)
+				}
+			}()
+		}
+	}()
+
+	c.Assert(testutils.WaitUntil(func() bool {
+		return atomic.LoadInt32(&completed) == 1000
+	}, 5*time.Second), check.IsNil)
+
+	log.Infof("%+v", a)
+	log.Infof("Total retries: %v", atomic.LoadInt32(&retries))
+}
+
+func (b *ControllerSuite) TestReservationCancel(c *check.C) {
+	a := NewAPILimiter("foo", APILimiterParameters{
+		RateLimit:           50.0,
+		RateBurst:           10,
+		ParallelRequests:    1,
+		MaxParallelRequests: 1,
+		MaxWaitDuration:     500 * time.Millisecond,
+		Log:                 true,
+	}, nil)
+
+	// Process a request but don't complete it, this will occupy the
+	// parallel request slot
+	req, err := a.Wait(context.Background())
+	c.Assert(err, check.IsNil)
+
+	var completed int32
+
+	// All of these requests must fail due to having to wait too long as
+	// the only parallel request slot is occupied. The rate limiter should
+	// not get occupied with these requests though.
+	for i := 0; i < 20; i++ {
+		go func() {
+			_, err := a.Wait(context.Background())
+			c.Assert(err, check.Not(check.IsNil))
+			atomic.AddInt32(&completed, 1)
+		}()
+	}
+
+	c.Assert(testutils.WaitUntil(func() bool {
+		return atomic.LoadInt32(&completed) == 20
+	}, time.Second), check.IsNil)
+
+	req.Done()
+
+	// All of these requests should now succeed
+	for i := 0; i < 10; i++ {
+		req2, err := a.Wait(context.Background())
+		c.Assert(err, check.IsNil)
+		req2.Done()
+	}
+}
diff --git a/pkg/redirectpolicy/manager_test.go b/pkg/redirectpolicy/manager_test.go
index cb59c39c4a..7ae6950f9d 100644
--- a/pkg/redirectpolicy/manager_test.go
+++ b/pkg/redirectpolicy/manager_test.go
@@ -58,6 +58,9 @@ type fakePodStore struct {
 }
 
 func (ps *fakePodStore) List() []interface{} {
+	if ps.OnList != nil {
+		return ps.OnList()
+	}
 	pods := make([]interface{}, 2, 2)
 	pods = append(pods, pod1, pod2)
 	return pods
@@ -96,20 +99,25 @@ func (ps *fakePodStore) Resync() error {
 }
 
 var (
-	tcpStr    = "TCP"
-	udpStr    = "UDP"
-	proto1, _ = lb.NewL4Type(tcpStr)
-	proto2, _ = lb.NewL4Type(udpStr)
-	fe1       = lb.NewL3n4Addr(
+	tcpStr = "TCP"
+	udpStr = "UDP"
+	proto1 = lb.NewL4Type(tcpStr)
+	proto2 = lb.NewL4Type(udpStr)
+	fe1    = lb.NewL3n4Addr(
 		proto1,
-		net.IP("1.1.1.1"),
+		net.ParseIP("1.1.1.1"),
 		80,
 		lb.ScopeExternal)
 	fe2 = lb.NewL3n4Addr(
 		proto2,
-		net.IP("2.2.2.2"),
+		net.ParseIP("2.2.2.2"),
 		81,
 		lb.ScopeExternal)
+	fe3v6 = lb.NewL3n4Addr(
+		proto1,
+		net.ParseIP("fd00::2"),
+		80,
+		lb.ScopeExternal)
 	portName1 = "test1"
 	portName2 = "test2"
 	beP1      = bePortInfo{
@@ -218,7 +226,8 @@ func (m *ManagerSuite) SetUpTest(c *C) {
 			Name:      "test-foo",
 			Namespace: "ns1",
 		},
-		lrpType: lrpConfigTypeAddr,
+		lrpType:      lrpConfigTypeAddr,
+		frontendType: addrFrontendSinglePort,
 		frontendMappings: []*feMapping{{
 			feAddr:      fe1,
 			podBackends: nil,
@@ -231,6 +240,7 @@ func (m *ManagerSuite) SetUpTest(c *C) {
 				},
 			},
 		},
+		backendPorts: []bePortInfo{beP1},
 	}
 	configSvcType = LRPConfig{
 		id: k8s.ServiceID{
@@ -284,8 +294,6 @@ func (m *ManagerSuite) TestManager_AddRedirectPolicy_SvcMatcherDuplicateConfig(c
 func (m *ManagerSuite) TestManager_AddrMatcherConfigSinglePort(c *C) {
 	// Add an addressMatcher type LRP with single port. The policy config
 	// frontend should have 2 pod backends with each of the podIPs.
-	configAddrType.frontendType = addrFrontendSinglePort
-	configAddrType.backendPorts = append(configAddrType.backendPorts, beP1)
 	podIPs, _ := utils.ValidIPs(pod1.Status)
 	expectedbes := make([]backend, len(podIPs))
 	for i := range podIPs {
@@ -314,7 +322,7 @@ func (m *ManagerSuite) TestManager_AddrMatcherConfigSinglePort(c *C) {
 	c.Assert(m.rpm.policyPods[pod1ID][0], Equals, configAddrType.id)
 
 	// Add a new backend pod, this will add 2 more pod backends with each of the podIPs.
-	pod3 := pod2
+	pod3 := pod2.DeepCopy()
 	pod3.Labels["test"] = "foo"
 	pod3ID := pod2ID
 	podIPs, _ = utils.ValidIPs(pod3.Status)
@@ -374,7 +382,13 @@ func (m *ManagerSuite) TestManager_AddrMatcherConfigMultiplePorts(c *C) {
 		beP1.name: &configAddrType.backendPorts[0],
 		beP2.name: &configAddrType.backendPorts[1]}
 	podIPs, _ := utils.ValidIPs(pod1.Status)
-	expectedbes := make([]backend, len(podIPs))
+	expectedbes := make([]backend, 0, len(podIPs))
+	for i := range podIPs {
+		expectedbes = append(expectedbes, backend{
+			L3n4Addr: lb.L3n4Addr{IP: net.ParseIP(podIPs[i]), L4Addr: beP1.l4Addr},
+			podID:    pod1ID,
+		})
+	}
 
 	added, err := m.rpm.AddRedirectPolicy(configAddrType, &fakePodStore{})
 
@@ -429,4 +443,59 @@ func (m *ManagerSuite) TestManager_AddrMatcherConfigMultiplePorts(c *C) {
 	c.Assert(len(m.rpm.policyConfigs), Equals, 0)
 }
 
+// Tests if frontend ipv4 and ipv6 addresses are mapped to the ipv4 and ipv6
+// backends, respectively.
+func (m *ManagerSuite) TestManager_AddrMatcherConfigDualStack(c *C) {
+	// Only ipv4 backend(s) for ipv4 frontend
+	pod3 := pod1.DeepCopy()
+	pod3ID := pod1ID
+	podIPs, _ := utils.ValidIPs(pod3.Status)
+	expectedbes4 := make([]backend, 0, len(podIPs))
+	for i := range podIPs {
+		expectedbes4 = append(expectedbes4, backend{
+			L3n4Addr: lb.L3n4Addr{IP: net.ParseIP(podIPs[i]), L4Addr: beP1.l4Addr},
+			podID:    pod3ID,
+		})
+	}
+	pod3v6 := slimcorev1.PodIP{IP: "fd00::40"}
+	expectedbes6 := []backend{{
+		L3n4Addr: lb.L3n4Addr{IP: net.ParseIP(pod3v6.IP), L4Addr: beP1.l4Addr},
+		podID:    pod3ID,
+	}}
+	pod3.Status.PodIPs = append(pod3.Status.PodIPs, pod3v6)
+	ps := &fakePodStore{OnList: func() []interface{} {
+		return []interface{}{pod3}
+	}}
+
+	added, err := m.rpm.AddRedirectPolicy(configAddrType, ps)
+
+	c.Assert(added, Equals, true)
+	c.Assert(err, IsNil)
+	c.Assert(len(configAddrType.frontendMappings[0].podBackends), Equals,
+		len(expectedbes4))
+	for i := range configAddrType.frontendMappings[0].podBackends {
+		c.Assert(configAddrType.frontendMappings[0].podBackends[i], checker.Equals,
+			expectedbes4[i])
+	}
+
+	// Only ipv6 backend(s) for ipv6 frontend
+	feM := []*feMapping{{
+		feAddr:      fe3v6,
+		podBackends: nil,
+	}}
+	configAddrType.id.Name = "test-bar"
+	configAddrType.frontendMappings = feM
+
+	added, err = m.rpm.AddRedirectPolicy(configAddrType, ps)
+
+	c.Assert(added, Equals, true)
+	c.Assert(err, IsNil)
+	c.Assert(len(configAddrType.frontendMappings[0].podBackends), Equals,
+		len(expectedbes6))
+	for i := range configAddrType.frontendMappings[0].podBackends {
+		c.Assert(configAddrType.frontendMappings[0].podBackends[i], checker.Equals,
+			expectedbes6[i])
+	}
+}
+
 //TODO Tests for svcMatcher
diff --git a/pkg/service/id_test.go b/pkg/service/id_test.go
index f6bc26d2d2..65cda1fca1 100644
--- a/pkg/service/id_test.go
+++ b/pkg/service/id_test.go
@@ -87,11 +87,10 @@ func (s *IDAllocTestSuite) TestServices(c *C) {
 	c.Assert(err, Equals, nil)
 	c.Assert(l3n4AddrID.ID, Equals, loadbalancer.ID(ffsIDu16+1))
 
-	// l3n4Addr3 should have the same ID as l3n4Addr2 since we are omitting the
-	// protocol type.
+	// different protocols should change the id
 	l3n4AddrID, err = AcquireID(l3n4Addr3, 0)
 	c.Assert(err, Equals, nil)
-	c.Assert(l3n4AddrID.ID, Equals, loadbalancer.ID(ffsIDu16+1))
+	c.Assert(l3n4AddrID.ID, Equals, loadbalancer.ID(ffsIDu16+2))
 
 	gotL3n4AddrID, err := GetID(FirstFreeServiceID)
 	c.Assert(err, Equals, nil)
diff --git a/pkg/service/service_test.go b/pkg/service/service_test.go
index 271e20b2fc..0b5fea4647 100644
--- a/pkg/service/service_test.go
+++ b/pkg/service/service_test.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/cilium/cilium/pkg/checker"
 	"github.com/cilium/cilium/pkg/cidr"
+	"github.com/cilium/cilium/pkg/loadbalancer"
 	lb "github.com/cilium/cilium/pkg/loadbalancer"
 	"github.com/cilium/cilium/pkg/maps/lbmap"
 	nodeTypes "github.com/cilium/cilium/pkg/node/types"
@@ -68,6 +69,7 @@ func (m *ManagerTestSuite) TearDownTest(c *C) {
 var (
 	frontend1 = *lb.NewL3n4AddrID(lb.TCP, net.ParseIP("1.1.1.1"), 80, lb.ScopeExternal, 0)
 	frontend2 = *lb.NewL3n4AddrID(lb.TCP, net.ParseIP("1.1.1.2"), 80, lb.ScopeExternal, 0)
+	frontend3 = *lb.NewL3n4AddrID(lb.UDP, net.ParseIP("1.1.1.2"), 80, lb.ScopeExternal, 0)
 	backends1 = []lb.Backend{
 		*lb.NewBackend(0, lb.TCP, net.ParseIP("10.0.0.1"), 8080),
 		*lb.NewBackend(0, lb.TCP, net.ParseIP("10.0.0.2"), 8080),
@@ -76,6 +78,10 @@ var (
 		*lb.NewBackend(0, lb.TCP, net.ParseIP("10.0.0.2"), 8080),
 		*lb.NewBackend(0, lb.TCP, net.ParseIP("10.0.0.3"), 8080),
 	}
+	backends3 = []lb.Backend{
+		*lb.NewBackend(0, lb.UDP, net.ParseIP("10.0.0.2"), 8080),
+		*lb.NewBackend(0, lb.UDP, net.ParseIP("10.0.0.3"), 8080),
+	}
 )
 
 func (m *ManagerTestSuite) TestUpsertAndDeleteService(c *C) {
@@ -170,9 +176,50 @@ func (m *ManagerTestSuite) TestUpsertAndDeleteService(c *C) {
 	c.Assert(len(m.lbmap.AffinityMatch[uint16(id2)]), Equals, 2)
 	c.Assert(len(m.lbmap.SourceRanges[uint16(id2)]), Equals, 2)
 
+	// Should add a similar service ot the others, different only by protocol;
+	// the other service(s) should not be corrupted/affected.
+	p3 := &lb.SVC{
+		Frontend:                  frontend3,
+		Backends:                  backends3,
+		Type:                      lb.SVCTypeLoadBalancer,
+		TrafficPolicy:             lb.SVCTrafficPolicyCluster,
+		SessionAffinity:           true,
+		SessionAffinityTimeoutSec: 300,
+		Name:                      "svc3",
+		Namespace:                 "ns2",
+		LoadBalancerSourceRanges:  []*cidr.CIDR{cidr1, cidr2},
+	}
+	created, id3, err := m.svc.UpsertService(p3)
+	c.Assert(err, IsNil)
+	c.Assert(created, Equals, true)
+	c.Assert(id3, Equals, lb.ID(3))
+	c.Assert(m.lbmap.ServiceByID[uint16(id3)].Frontend.Protocol, Equals, loadbalancer.UDP)
+	c.Assert(len(m.lbmap.ServiceByID[uint16(id3)].Backends), Equals, 2)
+	c.Assert(m.lbmap.ServiceByID[uint16(id3)].Backends[0].Protocol, Equals, loadbalancer.UDP)
+	c.Assert(m.lbmap.ServiceByID[uint16(id3)].Backends, Not(DeepEquals), m.lbmap.ServiceByID[uint16(id2)].Backends)
+	c.Assert(len(m.lbmap.BackendByID), Equals, 4)
+	c.Assert(m.svc.svcByID[id3].svcName, Equals, "svc3")
+	c.Assert(m.svc.svcByID[id3].svcNamespace, Equals, "ns2")
+	c.Assert(len(m.lbmap.AffinityMatch[uint16(id3)]), Equals, 2)
+	c.Assert(len(m.lbmap.SourceRanges[uint16(id3)]), Equals, 2)
+	// check that the similar service has not been overwritten
+	c.Assert(m.lbmap.ServiceByID[uint16(id2)].Frontend.Protocol, Equals, loadbalancer.TCP)
+	c.Assert(len(m.lbmap.ServiceByID[uint16(id2)].Backends), Equals, 2)
+	c.Assert(m.lbmap.ServiceByID[uint16(id2)].Backends[0].Protocol, Equals, loadbalancer.TCP)
+	c.Assert(m.svc.svcByID[id2].svcName, Equals, "svc2")
+	c.Assert(m.svc.svcByID[id2].svcNamespace, Equals, "ns2")
+	c.Assert(len(m.lbmap.AffinityMatch[uint16(id2)]), Equals, 2)
+	c.Assert(len(m.lbmap.SourceRanges[uint16(id2)]), Equals, 2)
+	// delete newest added service
+	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id3))
+	c.Assert(err, IsNil)
+	c.Assert(found, Equals, true)
+	c.Assert(len(m.lbmap.ServiceByID), Equals, 2)
+	c.Assert(len(m.lbmap.BackendByID), Equals, 2)
+	c.Assert(len(m.lbmap.AffinityMatch[uint16(id3)]), Equals, 0)
 	// Should remove the service and the backend, but keep another service and
 	// its backends. Also, should remove the affinity match.
-	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
+	found, err = m.svc.DeleteServiceByID(lb.ServiceID(id1))
 	c.Assert(err, IsNil)
 	c.Assert(found, Equals, true)
 	c.Assert(len(m.lbmap.ServiceByID), Equals, 1)
diff --git a/pkg/service/store/store_test.go b/pkg/service/store/store_test.go
index fdfb0ee470..bff6bb8db0 100644
--- a/pkg/service/store/store_test.go
+++ b/pkg/service/store/store_test.go
@@ -61,45 +61,45 @@ func (s *ServiceGenericSuite) TestPortConfigurationDeepEqual(c *check.C) {
 
 		{
 			a: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			b: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			want: true,
 		},
 		{
 			a: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			b: PortConfiguration{
-				"foz": {Protocol: loadbalancer.NONE, Port: 1},
+				"foz": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			want: false,
 		},
 		{
 			a: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			b: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 2},
+				"foo": {Protocol: loadbalancer.TCP, Port: 2},
 			},
 			want: false,
 		},
 		{
 			a: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			b: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
-				"baz": {Protocol: loadbalancer.NONE, Port: 2},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
+				"baz": {Protocol: loadbalancer.TCP, Port: 2},
 			},
 			want: false,
 		},
 		{
 			a: PortConfiguration{},
 			b: PortConfiguration{
-				"foo": {Protocol: loadbalancer.NONE, Port: 1},
+				"foo": {Protocol: loadbalancer.TCP, Port: 1},
 			},
 			want: false,
 		},
diff --git a/test/helpers/cilium.go b/test/helpers/cilium.go
index a0aa05c114..307fa748b2 100644
--- a/test/helpers/cilium.go
+++ b/test/helpers/cilium.go
@@ -799,9 +799,12 @@ func (s *SSHMeta) ServiceIsSynced(id int) (bool, error) {
 		return false, err
 	}
 
-	frontendAddr := net.JoinHostPort(
+	frontendAddr := serviceAddressKey(
 		svc.Status.Realized.FrontendAddress.IP,
-		fmt.Sprintf("%d", svc.Status.Realized.FrontendAddress.Port))
+		fmt.Sprintf("%d", svc.Status.Realized.FrontendAddress.Port),
+		svc.Status.Realized.FrontendAddress.Protocol,
+		"",
+	)
 	lb, ok := bpfLB[frontendAddr]
 	if ok == false {
 		return false, fmt.Errorf(
diff --git a/test/helpers/cons.go b/test/helpers/cons.go
index d10911de56..fd1663c436 100644
--- a/test/helpers/cons.go
+++ b/test/helpers/cons.go
@@ -22,7 +22,7 @@ import (
 
 	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
 	"github.com/cilium/cilium/pkg/versioncheck"
-	"github.com/cilium/cilium/test/ginkgo-ext"
+	ginkgoext "github.com/cilium/cilium/test/ginkgo-ext"
 )
 
 var (
diff --git a/test/helpers/kubectl.go b/test/helpers/kubectl.go
index 92cf6160da..e8ee77a958 100644
--- a/test/helpers/kubectl.go
+++ b/test/helpers/kubectl.go
@@ -1721,7 +1721,7 @@ func (kub *Kubectl) validateServicePlumbingInCiliumPod(fullName, ciliumPod strin
 	for _, port := range serviceObj.Spec.Ports {
 		var foundPort *v1.ServicePort
 		for _, realizedService := range realizedServices {
-			if port.Port == int32(realizedService.FrontendAddress.Port) {
+			if compareServicePortToFrontEnd(&port, realizedService.FrontendAddress) {
 				foundPort = &port
 				break
 			}
@@ -1730,8 +1730,8 @@ func (kub *Kubectl) validateServicePlumbingInCiliumPod(fullName, ciliumPod strin
 			return fmt.Errorf("port %d of service %s (%s) not found in cilium pod %s",
 				port.Port, fullName, serviceObj.Spec.ClusterIP, ciliumPod)
 		}
-
-		if _, ok := lbMap[net.JoinHostPort(serviceObj.Spec.ClusterIP, fmt.Sprintf("%d", port.Port))]; !ok {
+		lKey := serviceAddressKey(serviceObj.Spec.ClusterIP, fmt.Sprintf("%d", port.Port), string(port.Protocol), "")
+		if _, ok := lbMap[lKey]; !ok {
 			return fmt.Errorf("port %d of service %s (%s) not found in cilium bpf lb list of pod %s",
 				port.Port, fullName, serviceObj.Spec.ClusterIP, ciliumPod)
 		}
@@ -1743,10 +1743,11 @@ func (kub *Kubectl) validateServicePlumbingInCiliumPod(fullName, ciliumPod strin
 				foundBackend, foundBackendLB := false, false
 				for _, realizedService := range realizedServices {
 					frontEnd := realizedService.FrontendAddress
-					lb := lbMap[net.JoinHostPort(frontEnd.IP, fmt.Sprintf("%d", frontEnd.Port))]
-
+					lbKey := serviceAddressKey(frontEnd.IP, fmt.Sprintf("%d", frontEnd.Port), string(frontEnd.Protocol), "")
+					lb := lbMap[lbKey]
 					for _, backAddr := range realizedService.BackendAddresses {
-						if addr.IP == *backAddr.IP && uint16(port.Port) == backAddr.Port {
+						if addr.IP == *backAddr.IP && uint16(port.Port) == backAddr.Port &&
+							compareProto(string(port.Protocol), backAddr.Protocol) {
 							foundBackend = true
 							for _, backend := range lb {
 								if strings.Contains(backend, net.JoinHostPort(*backAddr.IP, fmt.Sprintf("%d", port.Port))) {
@@ -2845,41 +2846,47 @@ func (kub *Kubectl) CiliumPolicyAction(namespace, filepath string, action Resour
 	kub.Logger().Infof("Performing %s action on resource '%s'", action, filepath)
 
 	if status := kub.Action(action, filepath, namespace); !status.WasSuccessful() {
-		return "", status.GetErr(fmt.Sprintf("Cannot perform '%s' on resorce '%s'", action, filepath))
+		return "", status.GetErr(fmt.Sprintf("Cannot perform '%s' on resource '%s'", action, filepath))
 	}
 
 	// If policy is uninstalled we can't require a policy being enforced.
 	if action != KubectlDelete {
 		jqFilter := getPolicyEnforcingJqFilter(numNodes)
 		body := func() bool {
-			var data []map[string]string
-			cmd := fmt.Sprintf("%s get cnp --all-namespaces -o json | jq '%s'",
-				KubectlCmd, jqFilter)
-
-			res := kub.ExecShort(cmd)
-			if !res.WasSuccessful() {
-				kub.Logger().WithError(res.GetErr("")).Error("cannot get cnp status")
-				return false
+			cmds := map[string]string{
+				"CNP":  fmt.Sprintf("%s get cnp --all-namespaces -o json | jq '%s'", KubectlCmd, jqFilter),
+				"CCNP": fmt.Sprintf("%s get ccnp -o json | jq '%s'", KubectlCmd, jqFilter),
 			}
 
-			err := res.Unmarshal(&data)
-			if err != nil {
-				kub.Logger().WithError(err).Error("Cannot unmarshal json")
-				return false
-			}
+			for ctx, cmd := range cmds {
+				var data []map[string]string
 
-			for _, item := range data {
-				if item["enforcing"] != "true" || item["status"] != "true" {
-					kub.Logger().Errorf("Policy '%s' is not enforcing yet", item["name"])
+				res := kub.ExecShort(cmd)
+				if !res.WasSuccessful() {
+					kub.Logger().WithError(res.GetErr("")).Errorf("cannot get %s status", ctx)
 					return false
 				}
+
+				err := res.Unmarshal(&data)
+				if err != nil {
+					kub.Logger().WithError(err).Errorf("Cannot unmarshal json for %s status", ctx)
+					return false
+				}
+
+				for _, item := range data {
+					if item["enforcing"] != "true" || item["status"] != "true" {
+						kub.Logger().Errorf("%s policy '%s' is not enforcing yet", ctx, item["name"])
+						return false
+					}
+				}
 			}
+
 			return true
 		}
 
 		err = WithTimeout(
 			body,
-			"Timed out while waiting CNP to be enforced",
+			"Timed out while waiting for policies to be enforced",
 			&TimeoutConfig{Timeout: timeout})
 
 		if err != nil {
@@ -3747,7 +3754,7 @@ CILIUM_SERVICES:
 	for _, cSvc := range ciliumSvcs {
 		if cSvc.Status.Realized.FrontendAddress.IP == k8sService.Spec.ClusterIP {
 			for _, port := range k8sService.Spec.Ports {
-				if int32(cSvc.Status.Realized.FrontendAddress.Port) == port.Port {
+				if compareServicePortToFrontEnd(&port, cSvc.Status.Realized.FrontendAddress) {
 					ciliumService = &cSvc
 					break CILIUM_SERVICES
 				}
@@ -3768,7 +3775,11 @@ CILIUM_SERVICES:
 }
 
 // CiliumServiceAdd adds the given service on a 'pod' running Cilium
-func (kub *Kubectl) CiliumServiceAdd(pod string, id int64, frontend string, backends []string, svcType, trafficPolicy string) error {
+func (kub *Kubectl) CiliumServiceAdd(pod string, id int64, protocol string, frontend string, backends []string, svcType, trafficPolicy string) error {
+	protocol = strings.ToLower(protocol)
+	if protocol == "" || protocol == "any" || protocol == "none" {
+		protocol = "tcp"
+	}
 	var opts []string
 	switch strings.ToLower(svcType) {
 	case "nodeport":
@@ -3795,8 +3806,8 @@ func (kub *Kubectl) CiliumServiceAdd(pod string, id int64, frontend string, back
 	backendsStr := strings.Join(backends, ",")
 	ctx, cancel := context.WithTimeout(context.Background(), ShortCommandTimeout)
 	defer cancel()
-	return kub.CiliumExecContext(ctx, pod, fmt.Sprintf("cilium service update --id %d --frontend %q --backends %q %s",
-		id, frontend, backendsStr, optsStr)).GetErr("cilium service update")
+	return kub.CiliumExecContext(ctx, pod, fmt.Sprintf("cilium service update --id %d --protocol %q --frontend %q --backends %q %s",
+		id, protocol, frontend, backendsStr, optsStr)).GetErr("cilium service update")
 }
 
 // CiliumServiceDel deletes the service with 'id' on a 'pod' running Cilium
@@ -4020,7 +4031,7 @@ func validateCiliumSvc(cSvc models.Service, k8sSvcs []v1.Service, k8sEps []v1.En
 
 	var k8sServicePort *v1.ServicePort
 	for _, k8sPort := range k8sService.Spec.Ports {
-		if k8sPort.Port == int32(cSvc.Status.Realized.FrontendAddress.Port) {
+		if compareServicePortToFrontEnd(&k8sPort, cSvc.Status.Realized.FrontendAddress) {
 			k8sServicePort = &k8sPort
 			k8sServicesFound[serviceKey(*k8sService)] = true
 			break
@@ -4049,14 +4060,16 @@ func validateCiliumSvc(cSvc models.Service, k8sSvcs []v1.Service, k8sEps []v1.En
 }
 
 func validateCiliumSvcLB(cSvc models.Service, lbMap map[string][]string) error {
-	scope := ""
+	var scope string
 	if cSvc.Status.Realized.FrontendAddress.Scope == models.FrontendAddressScopeInternal {
 		scope = "/i"
 	}
-
-	frontendAddress := net.JoinHostPort(
+	frontendAddress := serviceAddressKey(
 		cSvc.Status.Realized.FrontendAddress.IP,
-		strconv.Itoa(int(cSvc.Status.Realized.FrontendAddress.Port))) + scope
+		strconv.Itoa(int(cSvc.Status.Realized.FrontendAddress.Port)),
+		cSvc.Status.Realized.FrontendAddress.Protocol,
+		scope,
+	)
 	bpfBackends, ok := lbMap[frontendAddress]
 	if !ok {
 		return fmt.Errorf("%s bpf lb map entry not found", frontendAddress)
@@ -4093,7 +4106,9 @@ func getK8sEndpointAddresses(ep v1.Endpoints) []*models.BackendAddress {
 }
 
 func addrsEqual(addr1, addr2 *models.BackendAddress) bool {
-	return *addr1.IP == *addr2.IP && addr1.Port == addr2.Port
+	return *addr1.IP == *addr2.IP &&
+		addr1.Port == addr2.Port &&
+		compareProto(addr1.Protocol, addr2.Protocol)
 }
 
 // GenerateNamespaceForTest generates a namespace based off of the current test
@@ -4224,3 +4239,36 @@ func (kub *Kubectl) CleanupCiliumComponents() {
 	}
 	wg.Wait()
 }
+
+func compareProto(proto1, proto2 string) bool {
+	proto1 = strings.ToLower(proto1)
+	if proto1 == "" || proto1 == "none" || proto1 == "any" {
+		return true
+	}
+	proto2 = strings.ToLower(proto2)
+	if proto2 == "" || proto2 == "none" || proto2 == "any" {
+		return true
+	}
+	return proto1 == proto2
+}
+
+func compareServicePortToFrontEnd(sP *v1.ServicePort, fA *models.FrontendAddress) bool {
+	return sP.Port == int32(fA.Port) && compareProto(string(sP.Protocol), fA.Protocol)
+}
+
+func compareBackendToFrontEnd(bA *models.BackendAddress, fA *models.FrontendAddress) bool {
+	return bA.Port == fA.Port && compareProto(bA.Protocol, fA.Protocol)
+}
+
+func serviceAddressKey(ip, port, proto, scope string) string {
+	newOutputStyle := HasNewServiceOutput(GetRunningCiliumVersion())
+	k := net.JoinHostPort(ip, port)
+	if newOutputStyle {
+		p := strings.ToLower(proto)
+		if p == "" || p == "none" || p == "any" {
+			proto = "NONE"
+		}
+		return fmt.Sprintf("%s/%s%s", k, proto, scope)
+	}
+	return fmt.Sprintf("%s%s", k, scope)
+}
diff --git a/test/helpers/utils.go b/test/helpers/utils.go
index 891daa9b39..9872a3ee29 100644
--- a/test/helpers/utils.go
+++ b/test/helpers/utils.go
@@ -39,8 +39,11 @@ import (
 	"golang.org/x/sys/unix"
 )
 
-// ensure that our random numbers are seeded differently on each run
-var randGen = rand.NewSafeRand(time.Now().UnixNano())
+var (
+	// ensure that our random numbers are seeded differently on each run
+	randGen              = rand.NewSafeRand(time.Now().UnixNano())
+	runningCiliumVersion string
+)
 
 // IsRunningOnJenkins detects if the currently running Ginkgo application is
 // most likely running in a Jenkins environment. Returns true if certain
@@ -60,6 +63,35 @@ func IsRunningOnJenkins() bool {
 	return result
 }
 
+// SetCiliumVersion sets the currently running cilium version
+// and returns a function that unsets it.
+func SetRunningCiliumVersion(v string) func() {
+	runningCiliumVersion = v
+	return func() {
+		runningCiliumVersion = ""
+	}
+}
+
+// GetRunningCiliumVersion gets the currently running cilium version.
+func GetRunningCiliumVersion() string {
+	return runningCiliumVersion
+}
+
+// HasNewServiceOutput checks to see if the current running cilium
+// version uses the old style service output (e.g. "0.0.0.0:53") vs
+// the new style (e.g. "0.0.0.0:53/TCP").
+func HasNewServiceOutput(ver string) bool {
+	cst, err := versioncheck.Version(ver)
+	// If the version is not parseable it is probably
+	// someone's custom build  or not set.
+	// Either way, it is probably using the new output
+	// format.
+	if err != nil {
+		return true
+	}
+	return versioncheck.MustCompile(">=1.9.0")(cst)
+}
+
 // Sleep sleeps for the specified duration in seconds
 func Sleep(delay time.Duration) {
 	time.Sleep(delay * time.Second)
@@ -218,6 +250,7 @@ func GetAppPods(apps []string, namespace string, kubectl *Kubectl, appFmt string
 		res, err := kubectl.GetPodNames(namespace, fmt.Sprintf("%s=%s", appFmt, v))
 		Expect(err).Should(BeNil())
 		Expect(res).Should(Not(BeNil()))
+		Expect(len(res)).To(BeNumerically(">", 0))
 		appPods[v] = res[0]
 		log.Infof("GetAppPods: pod=%q assigned to %q", res[0], v)
 	}
diff --git a/test/k8sT/DatapathConfiguration.go b/test/k8sT/DatapathConfiguration.go
index ea02487ce0..41a9734009 100644
--- a/test/k8sT/DatapathConfiguration.go
+++ b/test/k8sT/DatapathConfiguration.go
@@ -254,11 +254,10 @@ var _ = Describe("K8sDatapathConfig", func() {
 			Expect(testPodConnectivityAcrossNodes(kubectl)).Should(BeTrue(), "Connectivity test between nodes failed")
 		})
 
-		It("Check vxlan connectivity with per endpoint routes", func() {
-			Skip("Encapsulation mode is not supported with per-endpoint routes")
-
+		It("Check vxlan connectivity with per-endpoint routes", func() {
 			deploymentManager.DeployCilium(map[string]string{
-				"global.autoDirectNodeRoutes": "true",
+				"global.tunnel":                 "vxlan",
+				"global.endpointRoutes.enabled": "true",
 			}, DeployCiliumOptionsAndDNS)
 			Expect(testPodConnectivityAcrossNodes(kubectl)).Should(BeTrue(), "Connectivity test between nodes failed")
 
diff --git a/test/k8sT/Services.go b/test/k8sT/Services.go
index 6101b0028f..934acb661a 100644
--- a/test/k8sT/Services.go
+++ b/test/k8sT/Services.go
@@ -120,20 +120,20 @@ var _ = Describe("K8sServicesTest", func() {
 		return backends
 	}
 
-	ciliumAddService := func(id int64, frontend string, backends []string, svcType, trafficPolicy string) {
+	ciliumAddService := func(id int64, protocol string, frontend string, backends []string, svcType, trafficPolicy string) {
 		ciliumPods, err := kubectl.GetCiliumPods()
 		ExpectWithOffset(1, err).To(BeNil(), "Cannot get cilium pods")
 		for _, pod := range ciliumPods {
-			err := kubectl.CiliumServiceAdd(pod, id, frontend, backends, svcType, trafficPolicy)
+			err := kubectl.CiliumServiceAdd(pod, id, protocol, frontend, backends, svcType, trafficPolicy)
 			ExpectWithOffset(1, err).To(BeNil(), "Failed to add cilium service")
 		}
 	}
 
-	ciliumAddServiceOnNode := func(node string, id int64, frontend string, backends []string, svcType, trafficPolicy string) {
+	ciliumAddServiceOnNode := func(node string, id int64, protocol string, frontend string, backends []string, svcType, trafficPolicy string) {
 		ciliumPod, err := kubectl.GetCiliumPodOnNode(node)
 		ExpectWithOffset(1, err).To(BeNil(), fmt.Sprintf("Cannot get cilium pod on node %s", node))
 
-		err = kubectl.CiliumServiceAdd(ciliumPod, id, frontend, backends, svcType, trafficPolicy)
+		err = kubectl.CiliumServiceAdd(ciliumPod, id, protocol, frontend, backends, svcType, trafficPolicy)
 		ExpectWithOffset(1, err).To(BeNil(), fmt.Sprintf("Failed to add cilium service on node %s", node))
 	}
 
@@ -324,14 +324,14 @@ var _ = Describe("K8sServicesTest", func() {
 			BeforeAll(func() {
 				// Installs the IPv6 equivalent of app1-service (demo.yaml)
 				httpBackends := ciliumIPv6Backends("-l k8s:id=app1,k8s:io.kubernetes.pod.namespace=default", "80")
-				ciliumAddService(10080, net.JoinHostPort(demoClusterIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(10080, "tcp", net.JoinHostPort(demoClusterIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
 				tftpBackends := ciliumIPv6Backends("-l k8s:id=app1,k8s:io.kubernetes.pod.namespace=default", "69")
-				ciliumAddService(10069, net.JoinHostPort(demoClusterIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(10069, "udp", net.JoinHostPort(demoClusterIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
 				// Installs the IPv6 equivalent of echo (echo-svc.yaml)
 				httpBackends = ciliumIPv6Backends("-l k8s:name=echo,k8s:io.kubernetes.pod.namespace=default", "80")
-				ciliumAddService(20080, net.JoinHostPort(echoClusterIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(20080, "tcp", net.JoinHostPort(echoClusterIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
 				tftpBackends = ciliumIPv6Backends("-l k8s:name=echo,k8s:io.kubernetes.pod.namespace=default", "69")
-				ciliumAddService(20069, net.JoinHostPort(echoClusterIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(20069, "udp", net.JoinHostPort(echoClusterIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
 			})
 
 			AfterAll(func() {
@@ -347,7 +347,7 @@ var _ = Describe("K8sServicesTest", func() {
 				status.ExpectSuccess("cannot curl to service IP from host")
 
 				status = kubectl.ExecInHostNetNS(context.TODO(), k8s1NodeName,
-					helpers.CurlFail(`"tftp://[%s]/hello"`, demoClusterIPv6))
+					helpers.CurlFail(`"tftp://[%s]/hell"`, demoClusterIPv6))
 				status.ExpectSuccess("cannot curl to service IP from host")
 			})
 
@@ -460,9 +460,9 @@ var _ = Describe("K8sServicesTest", func() {
 			BeforeAll(func() {
 				// Install rules for testds-service (demo_ds.yaml)
 				httpBackends := ciliumIPv6Backends("-l k8s:zgroup=testDS,k8s:io.kubernetes.pod.namespace=default", "80")
-				ciliumAddService(31080, net.JoinHostPort(testDSIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(31080, "tcp", net.JoinHostPort(testDSIPv6, "80"), httpBackends, "ClusterIP", "Cluster")
 				tftpBackends := ciliumIPv6Backends("-l k8s:zgroup=testDS,k8s:io.kubernetes.pod.namespace=default", "69")
-				ciliumAddService(31069, net.JoinHostPort(testDSIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
+				ciliumAddService(31069, "udp", net.JoinHostPort(testDSIPv6, "69"), tftpBackends, "ClusterIP", "Cluster")
 			})
 
 			AfterAll(func() {
@@ -1365,21 +1365,21 @@ var _ = Describe("K8sServicesTest", func() {
 
 				// Install rules for testds-service NodePort Service(demo_ds.yaml)
 				httpBackends := ciliumIPv6Backends("-l k8s:zgroup=testDS,k8s:io.kubernetes.pod.namespace=default", "80")
-				ciliumAddService(31080, net.JoinHostPort(testDSIPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)), httpBackends, "NodePort", "Cluster")
-				ciliumAddService(31081, net.JoinHostPort("::", fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)), httpBackends, "NodePort", "Cluster")
+				ciliumAddService(31080, string(data.Spec.Ports[0].Protocol), net.JoinHostPort(testDSIPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)), httpBackends, "NodePort", "Cluster")
+				ciliumAddService(31081, string(data.Spec.Ports[0].Protocol), net.JoinHostPort("::", fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)), httpBackends, "NodePort", "Cluster")
 				// Add service corresponding to IPv6 address of the nodes so that they become
 				// reachable from outside the cluster.
-				ciliumAddServiceOnNode(helpers.K8s1, 31082, net.JoinHostPort(k8s1IPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)),
+				ciliumAddServiceOnNode(helpers.K8s1, 31082, string(data.Spec.Ports[0].Protocol), net.JoinHostPort(k8s1IPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)),
 					httpBackends, "NodePort", "Cluster")
-				ciliumAddServiceOnNode(helpers.K8s2, 31082, net.JoinHostPort(k8s2IPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)),
+				ciliumAddServiceOnNode(helpers.K8s2, 31082, string(data.Spec.Ports[0].Protocol), net.JoinHostPort(k8s2IPv6, fmt.Sprintf("%d", data.Spec.Ports[0].NodePort)),
 					httpBackends, "NodePort", "Cluster")
 
 				tftpBackends := ciliumIPv6Backends("-l k8s:zgroup=testDS,k8s:io.kubernetes.pod.namespace=default", "69")
-				ciliumAddService(31069, net.JoinHostPort(testDSIPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)), tftpBackends, "NodePort", "Cluster")
-				ciliumAddService(31070, net.JoinHostPort("::", fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)), tftpBackends, "NodePort", "Cluster")
-				ciliumAddServiceOnNode(helpers.K8s1, 31071, net.JoinHostPort(k8s1IPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)),
+				ciliumAddService(31069, string(data.Spec.Ports[1].Protocol), net.JoinHostPort(testDSIPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)), tftpBackends, "NodePort", "Cluster")
+				ciliumAddService(31070, string(data.Spec.Ports[1].Protocol), net.JoinHostPort("::", fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)), tftpBackends, "NodePort", "Cluster")
+				ciliumAddServiceOnNode(helpers.K8s1, 31071, string(data.Spec.Ports[1].Protocol), net.JoinHostPort(k8s1IPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)),
 					tftpBackends, "NodePort", "Cluster")
-				ciliumAddServiceOnNode(helpers.K8s2, 31071, net.JoinHostPort(k8s2IPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)),
+				ciliumAddServiceOnNode(helpers.K8s2, 31071, string(data.Spec.Ports[1].Protocol), net.JoinHostPort(k8s2IPv6, fmt.Sprintf("%d", data.Spec.Ports[1].NodePort)),
 					tftpBackends, "NodePort", "Cluster")
 			})
 
diff --git a/test/k8sT/Updates.go b/test/k8sT/Updates.go
index efbd56699a..7602fcf936 100644
--- a/test/k8sT/Updates.go
+++ b/test/k8sT/Updates.go
@@ -142,6 +142,8 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 	var (
 		privateIface string // only used when running w/o kube-proxy
 		err          error
+		apps         = []string{helpers.App1, helpers.App2, helpers.App3}
+		app1Service  = "app1-service"
 	)
 
 	canRun, err := helpers.CanRunK8sVersion(oldImageVersion, helpers.GetCurrentK8SEnv())
@@ -160,9 +162,6 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 		ExpectWithOffset(1, err).To(BeNil(), "Unable to determine private iface")
 	}
 
-	apps := []string{helpers.App1, helpers.App2, helpers.App3}
-	app1Service := "app1-service"
-
 	cleanupCiliumState := func(helmPath, chartVersion, imageName, imageTag, registry string) {
 		removeCilium(kubectl)
 
@@ -290,6 +289,8 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 				helpers.CiliumNamespace,
 				opts)
 		}, time.Second*30, time.Second*1).Should(helpers.CMDSuccess(), fmt.Sprintf("Cilium %q was not able to be deployed", oldHelmChartVersion))
+		unsetFn := helpers.SetRunningCiliumVersion(oldImageVersion)
+		defer unsetFn()
 
 		// Cilium is only ready if kvstore is ready, the kvstore is ready if
 		// kube-dns is running.
@@ -369,7 +370,7 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 			if lastCount == -1 {
 				lastCount = currentCount
 			}
-			Expect(lastCount).Should(BeIdenticalTo(currentCount),
+			ExpectWithOffset(1, lastCount).Should(BeIdenticalTo(currentCount),
 				"migrate-svc restart count values do not match")
 		}
 
@@ -379,23 +380,23 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 		ExpectWithOffset(1, res).To(helpers.CMDSuccess(), "cannot apply dempo application")
 
 		err = kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=testapp", timeout)
-		Expect(err).Should(BeNil(), "Test pods are not ready after timeout")
+		ExpectWithOffset(1, err).Should(BeNil(), "Test pods are not ready after timeout")
 
 		_, err = kubectl.CiliumPolicyAction(
 			helpers.DefaultNamespace, l7Policy, helpers.KubectlApply, timeout)
-		Expect(err).Should(BeNil(), "cannot import l7 policy: %v", l7Policy)
+		ExpectWithOffset(1, err).Should(BeNil(), "cannot import l7 policy: %v", l7Policy)
 
 		By("Creating service and clients for migration")
 
 		res = kubectl.ApplyDefault(migrateSVCServer)
 		ExpectWithOffset(1, res).To(helpers.CMDSuccess(), "cannot apply migrate-svc-server")
 		err = kubectl.WaitforPods(helpers.DefaultNamespace, "-l app=migrate-svc-server", timeout)
-		Expect(err).Should(BeNil(), "migrate-svc-server pods are not ready after timeout")
+		ExpectWithOffset(1, err).Should(BeNil(), "migrate-svc-server pods are not ready after timeout")
 
 		res = kubectl.ApplyDefault(migrateSVCClient)
 		ExpectWithOffset(1, res).To(helpers.CMDSuccess(), "cannot apply migrate-svc-client")
 		err = kubectl.WaitforPods(helpers.DefaultNamespace, "-l app=migrate-svc-client", timeout)
-		Expect(err).Should(BeNil(), "migrate-svc-client pods are not ready after timeout")
+		ExpectWithOffset(1, err).Should(BeNil(), "migrate-svc-client pods are not ready after timeout")
 
 		validateEndpointsConnection()
 		checkNoInteruptsInSVCFlows()
@@ -498,6 +499,7 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 				helpers.CiliumNamespace,
 				opts)
 		}, time.Second*30, time.Second*1).Should(helpers.CMDSuccess(), fmt.Sprintf("Cilium %q was not able to be deployed", newHelmChartVersion))
+		helpers.SetRunningCiliumVersion(newImageVersion)
 
 		By("Validating pods have the right image version upgraded")
 		err = helpers.WithTimeout(
@@ -532,6 +534,7 @@ func InstallAndValidateCiliumUpgrades(kubectl *helpers.Kubectl, oldHelmChartVers
 			"Cilium Pods are not updating correctly",
 			&helpers.TimeoutConfig{Timeout: timeout})
 		ExpectWithOffset(1, err).To(BeNil(), "Pods are not updating")
+		helpers.SetRunningCiliumVersion(oldImageVersion)
 
 		err = kubectl.WaitforPods(
 			helpers.CiliumNamespace, "-l k8s-app=cilium", timeout)
diff --git a/test/kubernetes-test.sh b/test/kubernetes-test.sh
index a4a499d0bd..7ab96e18b4 100755
--- a/test/kubernetes-test.sh
+++ b/test/kubernetes-test.sh
@@ -73,6 +73,10 @@ export KUBE_MASTER=192.168.36.11
 export KUBE_MASTER_IP=192.168.36.11
 export KUBE_MASTER_URL="https://192.168.36.11:6443"
 
+echo "Running upstream services conformance tests"
+${HOME}/go/bin/kubetest --provider=local --test \
+  --test_args="--ginkgo.focus=Services.*\[Conformance\].* --e2e-verify-service-account=false --host ${KUBE_MASTER_URL}"
+
 # We currently skip the following tests:
 # should not allow access by TCP when a policy specifies only SCTP
 #  - Cilium does not support SCTP yet
@@ -81,4 +85,6 @@ export KUBE_MASTER_URL="https://192.168.36.11:6443"
 #  - TL;DR Cilium does not allow to specify pod CIDRs as part of the policy
 #    because it conflicts with the pod's security identity.
 #  - More info at https://github.com/cilium/cilium/issues/9209
-${HOME}/go/bin/kubetest --provider=local --test --test_args="--ginkgo.focus=NetworkPolicy.* --e2e-verify-service-account=false --host ${KUBE_MASTER_URL} --ginkgo.skip=(should.ensure.an.IP.overlapping.both.IPBlock.CIDR.and.IPBlock.Except.is.allowed)|(should.allow.egress.access.to.server.in.CIDR.block)|(should.not.allow.access.by.TCP.when.a.policy.specifies.only.SCTP)"
+echo "Running upstream NetworkPolicy tests"
+${HOME}/go/bin/kubetest --provider=local --test \
+  --test_args="--ginkgo.focus=NetworkPolicy.* --e2e-verify-service-account=false --host ${KUBE_MASTER_URL} --ginkgo.skip=(should.ensure.an.IP.overlapping.both.IPBlock.CIDR.and.IPBlock.Except.is.allowed)|(should.allow.egress.access.to.server.in.CIDR.block)|(should.not.allow.access.by.TCP.when.a.policy.specifies.only.SCTP)"
diff --git a/test/provision/manifest/1.19/coredns_deployment.yaml b/test/provision/manifest/1.19/coredns_deployment.yaml
index 39fffbb5bb..80011421a1 100644
--- a/test/provision/manifest/1.19/coredns_deployment.yaml
+++ b/test/provision/manifest/1.19/coredns_deployment.yaml
@@ -77,13 +77,14 @@ data:
         ready
         kubernetes cluster.local in-addr.arpa ip6.arpa {
             pods insecure
-            ttl 0
             fallthrough in-addr.arpa ip6.arpa
+            ttl 30
         }
+        prometheus :9153
         forward . /etc/resolv.conf {
-            max_fails 0
+            max_concurrent 1000
         }
-        prometheus :9153
+        cache 30
         loop
         reload
         loadbalance