From 3056247ae51aad79b5b852d7f28637174c7e3f7b Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Tue, 5 Aug 2025 15:33:18 -0700 Subject: [PATCH 01/15] add dscp values --- api/pkg/lib/numorstring/dscp.go | 130 ++++ api/pkg/openapi/generated.openapi.go | 12 + felix/calc/event_sequencer.go | 12 +- felix/dataplane/linux/int_dataplane.go | 3 + felix/dataplane/linux/masq_mgr.go | 8 +- felix/dataplane/linux/qos/qos.go | 5 + felix/dataplane/linux/qos_policy_mgr.go | 121 +++ felix/dataplane/linux/qos_policy_mgr_test.go | 201 +++++ felix/fv/infrastructure/infra_k8s.go | 7 +- felix/fv/qos_policy_test.go | 394 ++++++++++ felix/generictables/actions.go | 1 + felix/iptables/actions.go | 18 + felix/iptables/actions_test.go | 4 +- felix/nftables/actions.go | 23 + felix/nftables/actions_test.go | 4 +- felix/proto/felixbackend.pb.go | 688 ++++++++++-------- felix/proto/felixbackend.proto | 6 + felix/rules/nat.go | 4 +- felix/rules/qos.go | 36 + felix/rules/qos_test.go | 106 +++ felix/rules/rule_defs.go | 7 +- felix/rules/static.go | 10 + felix/rules/static_test.go | 7 + libcalico-go/lib/apis/v3/generated.openapi.go | 7 + libcalico-go/lib/apis/v3/workloadendpoint.go | 4 +- .../lib/apis/v3/zz_generated.deepcopy.go | 7 +- .../lib/backend/k8s/conversion/constants.go | 3 +- .../conversion/workload_endpoint_default.go | 8 +- 28 files changed, 1510 insertions(+), 326 deletions(-) create mode 100644 api/pkg/lib/numorstring/dscp.go create mode 100644 felix/dataplane/linux/qos_policy_mgr.go create mode 100644 felix/dataplane/linux/qos_policy_mgr_test.go create mode 100644 felix/fv/qos_policy_test.go create mode 100644 felix/rules/qos.go create mode 100644 felix/rules/qos_test.go diff --git a/api/pkg/lib/numorstring/dscp.go b/api/pkg/lib/numorstring/dscp.go new file mode 100644 index 00000000000..cc3755f9d0c --- /dev/null +++ b/api/pkg/lib/numorstring/dscp.go @@ -0,0 +1,130 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package numorstring + +import "strings" + +const ( + // Default forwarding, i.e. best effort. + DF = "DF" // DSCP value 0 + + // Expedited Forwarding + EF = "EF" // DSCP value 46 + + // Assured Forwarding + AF11 = "AF11" // DSCP value 10 + AF12 = "AF12" // DSCP value 12 + AF13 = "AF13" // DSCP value 14 + + AF21 = "AF21" // DSCP value 18 + AF22 = "AF22" // DSCP value 20 + AF23 = "AF23" // DSCP value 22 + + AF31 = "AF31" // DSCP value 26 + AF32 = "AF32" // DSCP value 28 + AF33 = "AF33" // DSCP value 30 + + AF41 = "AF41" // DSCP value 34 + AF42 = "AF42" // DSCP value 36 + AF43 = "AF43" // DSCP value 38 + + // Class selectors, defined in RFC for backward compatibility with IP precedence. + CS0 = "CS0" // DSCP value 0, similar to DF + CS1 = "CS1" // DSCP value 8 + CS2 = "CS2" // DSCP value 16 + CS3 = "CS3" // DSCP value 24 + CS4 = "CS4" // DSCP value 32 + CS5 = "CS5" // DSCP value 40 + CS6 = "CS6" // DSCP value 48 +) + +var ( + AllDSCPValues = map[string]uint8{ + DF: 0, + EF: 46, + + AF11: 10, AF12: 12, AF13: 14, + AF21: 18, AF22: 20, AF23: 22, + AF31: 26, AF32: 28, AF33: 30, + AF41: 34, AF42: 36, AF43: 38, + + CS0: 0, CS1: 8, CS2: 16, + CS3: 24, CS4: 32, CS5: 40, + CS6: 48, + } +) + +type DSCP Uint8OrString + +// DSCPFromInt creates a DSCP struct from an integer value. +func DSCPFromInt(v uint8) DSCP { + return DSCP( + Uint8OrString{Type: NumOrStringNum, NumVal: v}, + ) +} + +// DSCPFromString creates a DSCP struct from a string value. +func DSCPFromString(s string) DSCP { + for k, _ := range AllDSCPValues { + if strings.EqualFold(k, s) { + return DSCP( + Uint8OrString{Type: NumOrStringString, StrVal: s}, + ) + } + } + + // Unknown protocol - return the value unchanged. Validation should catch this. + return DSCP( + Uint8OrString{Type: NumOrStringString, StrVal: s}, + ) +} + +func (d *DSCP) ToUint8() uint8 { + val, err := (*Uint8OrString)(d).NumValue() + if err == nil { + return val + } + + val, valid := AllDSCPValues[d.StrVal] + if !valid { + return 0 + } + return val +} + +// UnmarshalJSON implements the json.Unmarshaller interface. +func (d *DSCP) UnmarshalJSON(b []byte) error { + return (*Uint8OrString)(d).UnmarshalJSON(b) +} + +// MarshalJSON implements the json.Marshaller interface. +func (d DSCP) MarshalJSON() ([]byte, error) { + return Uint8OrString(d).MarshalJSON() +} + +// String returns the string value, or the Itoa of the int value. +func (d DSCP) String() string { + return (Uint8OrString)(d).String() +} + +// OpenAPISchemaType is used by the kube-openapi generator when constructing +// the OpenAPI spec of this type. +// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators +func (_ DSCP) OpenAPISchemaType() []string { return []string{"string"} } + +// OpenAPISchemaFormat is used by the kube-openapi generator when constructing +// the OpenAPI spec of this type. +// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators +func (_ DSCP) OpenAPISchemaFormat() string { return "int-or-string" } diff --git a/api/pkg/openapi/generated.openapi.go b/api/pkg/openapi/generated.openapi.go index 65cec331f3f..04cb83cea74 100644 --- a/api/pkg/openapi/generated.openapi.go +++ b/api/pkg/openapi/generated.openapi.go @@ -124,6 +124,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/projectcalico/api/pkg/apis/projectcalico/v3.TierList": schema_pkg_apis_projectcalico_v3_TierList(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.TierSpec": schema_pkg_apis_projectcalico_v3_TierSpec(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.WorkloadEndpointControllerConfig": schema_pkg_apis_projectcalico_v3_WorkloadEndpointControllerConfig(ref), + "github.com/projectcalico/api/pkg/lib/numorstring.DSCP": schema_api_pkg_lib_numorstring_DSCP(ref), "github.com/projectcalico/api/pkg/lib/numorstring.Port": schema_api_pkg_lib_numorstring_Port(ref), "github.com/projectcalico/api/pkg/lib/numorstring.Protocol": schema_api_pkg_lib_numorstring_Protocol(ref), "github.com/projectcalico/api/pkg/lib/numorstring.Uint8OrString": schema_api_pkg_lib_numorstring_Uint8OrString(ref), @@ -6639,6 +6640,17 @@ func schema_pkg_apis_projectcalico_v3_WorkloadEndpointControllerConfig(ref commo } } +func schema_api_pkg_lib_numorstring_DSCP(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: numorstring.DSCP{}.OpenAPISchemaType(), + Format: numorstring.DSCP{}.OpenAPISchemaFormat(), + }, + }, + } +} + func schema_api_pkg_lib_numorstring_Port(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/felix/calc/event_sequencer.go b/felix/calc/event_sequencer.go index f2961b4261b..68329bc89fc 100644 --- a/felix/calc/event_sequencer.go +++ b/felix/calc/event_sequencer.go @@ -400,7 +400,10 @@ func ModelWorkloadEndpointToProto(ep *model.WorkloadEndpoint, peerData *Endpoint if ep.Mac != nil { mac = ep.Mac.String() } - var qosControls *proto.QoSControls + var ( + qosControls *proto.QoSControls + qosPolicies []*proto.QoSPolicy + ) if ep.QoSControls != nil { qosControls = &proto.QoSControls{ IngressBandwidth: ep.QoSControls.IngressBandwidth, @@ -418,6 +421,12 @@ func ModelWorkloadEndpointToProto(ep *model.WorkloadEndpoint, peerData *Endpoint IngressMaxConnections: ep.QoSControls.IngressMaxConnections, EgressMaxConnections: ep.QoSControls.EgressMaxConnections, } + + if ep.QoSControls.DSCP != nil { + qosPolicies = append(qosPolicies, &proto.QoSPolicy{ + Dscp: int32(ep.QoSControls.DSCP.ToUint8()), + }) + } } var localBGPPeer *proto.LocalBGPPeer @@ -454,6 +463,7 @@ func ModelWorkloadEndpointToProto(ep *model.WorkloadEndpoint, peerData *Endpoint QosControls: qosControls, LocalBgpPeer: localBGPPeer, SkipRedir: skipRedir, + QosPolicies: qosPolicies, } } diff --git a/felix/dataplane/linux/int_dataplane.go b/felix/dataplane/linux/int_dataplane.go index 17e310a9ba7..6eb536ee502 100644 --- a/felix/dataplane/linux/int_dataplane.go +++ b/felix/dataplane/linux/int_dataplane.go @@ -1098,6 +1098,8 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { dp.endpointsSourceV4 = epManager dp.RegisterManager(newFloatingIPManager(natTableV4, ruleRenderer, 4, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV4, natTableV4, ruleRenderer, config.MaxIPSetSize, 4)) + dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) + if config.RulesConfig.IPIPEnabled { log.Info("IPIP enabled, starting thread to keep tunnel configuration in sync.") // Add a manager to keep the all-hosts IP set up to date. @@ -1293,6 +1295,7 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { )) dp.RegisterManager(newFloatingIPManager(natTableV6, ruleRenderer, 6, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV6, natTableV6, ruleRenderer, config.MaxIPSetSize, 6)) + dp.RegisterManager(newQoSPolicyManager(mangleTableV6, ruleRenderer, 6)) dp.RegisterManager(newServiceLoopManager(filterTableV6, ruleRenderer, 6)) // Add a manager for IPv6 wireguard configuration. This is added irrespective of whether wireguard is actually enabled diff --git a/felix/dataplane/linux/masq_mgr.go b/felix/dataplane/linux/masq_mgr.go index d0c00c2c32e..947bd0a8453 100644 --- a/felix/dataplane/linux/masq_mgr.go +++ b/felix/dataplane/linux/masq_mgr.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 Tigera, Inc. All rights reserved. +// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ func newMasqManager( // in sync, by which point we'll have added all our CIDRs into the sets. ipsetsDataplane.AddOrReplaceIPSet(ipsets.IPSetMetadata{ MaxSize: maxIPSetSize, - SetID: rules.IPSetIDNATOutgoingAllPools, + SetID: rules.IPSetIDAllPools, Type: ipsets.IPSetTypeHashNet, }, []string{}) ipsetsDataplane.AddOrReplaceIPSet(ipsets.IPSetMetadata{ @@ -105,7 +105,7 @@ func (d *masqManager) OnUpdate(msg interface{}) { // defers and coalesces the update so removing then adding the // same IP is a no-op anyway. logCxt.Debug("Removing old pool.") - d.ipsetsDataplane.RemoveMembers(rules.IPSetIDNATOutgoingAllPools, []string{oldPool.Cidr}) + d.ipsetsDataplane.RemoveMembers(rules.IPSetIDAllPools, []string{oldPool.Cidr}) if oldPool.Masquerade { logCxt.Debug("Masquerade was enabled on pool.") d.ipsetsDataplane.RemoveMembers(rules.IPSetIDNATOutgoingMasqPools, []string{oldPool.Cidr}) @@ -124,7 +124,7 @@ func (d *masqManager) OnUpdate(msg interface{}) { // Update the IP sets. logCxt.Debug("Adding IPAM pool to IP sets.") - d.ipsetsDataplane.AddMembers(rules.IPSetIDNATOutgoingAllPools, []string{newPool.Cidr}) + d.ipsetsDataplane.AddMembers(rules.IPSetIDAllPools, []string{newPool.Cidr}) if newPool.Masquerade { logCxt.Debug("IPAM has masquerade enabled.") d.ipsetsDataplane.AddMembers(rules.IPSetIDNATOutgoingMasqPools, []string{newPool.Cidr}) diff --git a/felix/dataplane/linux/qos/qos.go b/felix/dataplane/linux/qos/qos.go index 423edef68a3..441f9dd3754 100644 --- a/felix/dataplane/linux/qos/qos.go +++ b/felix/dataplane/linux/qos/qos.go @@ -485,3 +485,8 @@ func updateTBF(tbs *TokenBucketState, workloadDevice netlink.Link) error { } return nil } + +type Policy struct { + SrcAddrs string + DSCP uint8 +} diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go new file mode 100644 index 00000000000..e107255f3ba --- /dev/null +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -0,0 +1,121 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package intdataplane + +import ( + "sort" + "strings" + + "github.com/sirupsen/logrus" + + "github.com/projectcalico/calico/felix/dataplane/linux/qos" + "github.com/projectcalico/calico/felix/proto" + "github.com/projectcalico/calico/felix/rules" + "github.com/projectcalico/calico/felix/types" +) + +type qosPolicyManager struct { + ipVersion uint8 + ruleRenderer rules.RuleRenderer + + // QoS policy + mangleTable Table + dirty bool + qosPolicies map[types.WorkloadEndpointID]qos.Policy + + logCxt *logrus.Entry +} + +func newQoSPolicyManager( + mangleTable Table, + ruleRenderer rules.RuleRenderer, + ipVersion uint8, +) *qosPolicyManager { + return &qosPolicyManager{ + ipVersion: ipVersion, + qosPolicies: map[types.WorkloadEndpointID]qos.Policy{}, + dirty: true, + mangleTable: mangleTable, + ruleRenderer: ruleRenderer, + logCxt: logrus.WithField("ipVersion", ipVersion), + } +} + +func (m *qosPolicyManager) OnUpdate(msg interface{}) { + switch msg := msg.(type) { + case *proto.WorkloadEndpointUpdate: + m.handleWlEndpointUpdates(msg.GetId(), msg) + case *proto.WorkloadEndpointRemove: + m.handleWlEndpointUpdates(msg.GetId(), nil) + } +} + +func (m *qosPolicyManager) handleWlEndpointUpdates(wlID *proto.WorkloadEndpointID, msg *proto.WorkloadEndpointUpdate) { + id := types.ProtoToWorkloadEndpointID(wlID) + if msg == nil || len(msg.Endpoint.QosPolicies) == 0 { + _, exists := m.qosPolicies[id] + if exists { + delete(m.qosPolicies, id) + m.dirty = true + } + return + } + + // We only support one policy per endpoint at this point. + dscp := msg.Endpoint.QosPolicies[0].Dscp + + // This situation must be handled earlier. + if dscp > 63 || dscp < 0 { + logrus.WithField("id", id).Panicf("Invalid DSCP value %v", dscp) + } + ips := msg.Endpoint.Ipv4Nets + if m.ipVersion == 6 { + ips = msg.Endpoint.Ipv6Nets + } + if len(ips) != 0 { + m.qosPolicies[id] = qos.Policy{ + SrcAddrs: normaliseSourceAddr(ips), + DSCP: uint8(dscp), + } + m.dirty = true + } +} + +func normaliseSourceAddr(addrs []string) string { + var trimmedSources []string + for _, addr := range addrs { + parts := strings.Split(addr, "/") + trimmedSources = append(trimmedSources, parts[0]) + } + return strings.Join(trimmedSources, ",") +} + +func (m *qosPolicyManager) CompleteDeferredWork() error { + if m.dirty { + var policies []qos.Policy + for _, p := range m.qosPolicies { + policies = append(policies, p) + } + sort.Slice(policies, func(i, j int) bool { + return policies[i].SrcAddrs < policies[j].SrcAddrs + }) + + chain := m.ruleRenderer.EgressQoSPolicyChain(policies, m.ipVersion) + m.mangleTable.UpdateChain(chain) + m.dirty = false + } + + return nil +} diff --git a/felix/dataplane/linux/qos_policy_mgr_test.go b/felix/dataplane/linux/qos_policy_mgr_test.go new file mode 100644 index 00000000000..964ebfa7ce1 --- /dev/null +++ b/felix/dataplane/linux/qos_policy_mgr_test.go @@ -0,0 +1,201 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package intdataplane + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/projectcalico/calico/felix/generictables" + "github.com/projectcalico/calico/felix/ipsets" + "github.com/projectcalico/calico/felix/iptables" + "github.com/projectcalico/calico/felix/proto" + "github.com/projectcalico/calico/felix/rules" +) + +var _ = Describe("QoS policy manager", func() { + var ( + manager *qosPolicyManager + mangleTable *mockTable + ruleRenderer rules.RuleRenderer + ) + + BeforeEach(func() { + mangleTable = newMockTable("mangle") + ruleRenderer = rules.NewRenderer(rules.Config{ + IPSetConfigV4: ipsets.NewIPVersionConfig( + ipsets.IPFamilyV4, + "cali", + nil, + nil, + ), + MarkPass: 0x1, + MarkAccept: 0x2, + MarkScratch0: 0x4, + MarkScratch1: 0x8, + MarkDrop: 0x10, + MarkEndpoint: 0x11110000, + }) + manager = newQoSPolicyManager(mangleTable, ruleRenderer, 4) + }) + + Describe("QoS policy: after adding a workload with DSCP annotation", func() { + BeforeEach(func() { + manager.OnUpdate(&proto.IPAMPoolUpdate{ + Id: "pool-1", + Pool: &proto.IPAMPool{ + Cidr: "10.0.0.0/16", + }, + }) + err := manager.CompleteDeferredWork() + Expect(err).ToNot(HaveOccurred()) + }) + + It("should program QoS policy chain with no rule", func() { + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: nil, + }}}) + }) + + It("should handle workload updates correctly", func() { + By("sending workload endpoint updates with DSCP annotion") + manager.OnUpdate(&proto.WorkloadEndpointUpdate{ + Id: &wlEPID1, + Endpoint: &proto.WorkloadEndpoint{ + State: "active", + Name: "cali12345-ab", + Ipv4Nets: []string{"10.0.240.2/24"}, + Ipv6Nets: []string{"2001:db8:2::2/128"}, + QosPolicies: []*proto.QoSPolicy{{Dscp: 44}}, + }, + }) + + err := manager.CompleteDeferredWork() + Expect(err).NotTo(HaveOccurred()) + + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: []generictables.Rule{ + { + Action: iptables.DSCPAction{Value: 44}, + Match: iptables.Match(). + SourceNet("10.0.240.2"), + }, + }, + }}}) + + By("sending another workload endpoint updates with DSCP annotion") + manager.OnUpdate(&proto.WorkloadEndpointUpdate{ + Id: &wlEPID2, + Endpoint: &proto.WorkloadEndpoint{ + State: "active", + Name: "cali2", + Ipv4Nets: []string{"10.0.240.3/24"}, + Ipv6Nets: []string{"2001:db8:2::3/128"}, + QosPolicies: []*proto.QoSPolicy{{Dscp: 20}}, + }, + }) + + err = manager.CompleteDeferredWork() + Expect(err).NotTo(HaveOccurred()) + + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: []generictables.Rule{ + { + Action: iptables.DSCPAction{Value: 44}, + Match: iptables.Match(). + SourceNet("10.0.240.2"), + }, + { + Action: iptables.DSCPAction{Value: 20}, + Match: iptables.Match(). + SourceNet("10.0.240.3"), + }, + }, + }}}) + + By("verifying update to DSCP value takes effect") + manager.OnUpdate(&proto.WorkloadEndpointUpdate{ + Id: &wlEPID1, + Endpoint: &proto.WorkloadEndpoint{ + State: "active", + Name: "cali12345-ab", + Ipv4Nets: []string{"10.0.240.2/24"}, + Ipv6Nets: []string{"2001:db8:2::2/128"}, + QosPolicies: []*proto.QoSPolicy{{Dscp: 13}}, + }, + }) + + err = manager.CompleteDeferredWork() + Expect(err).NotTo(HaveOccurred()) + + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: []generictables.Rule{ + { + Action: iptables.DSCPAction{Value: 13}, + Match: iptables.Match(). + SourceNet("10.0.240.2"), + }, + { + Action: iptables.DSCPAction{Value: 20}, + Match: iptables.Match(). + SourceNet("10.0.240.3"), + }, + }, + }}}) + + By("verifying QoS policy rules removed when annotation is removed") + manager.OnUpdate(&proto.WorkloadEndpointUpdate{ + Id: &wlEPID1, + Endpoint: &proto.WorkloadEndpoint{ + State: "active", + Name: "cali12345-ab", + Ipv4Nets: []string{"10.0.240.2/24"}, + Ipv6Nets: []string{"2001:db8:2::2/128"}, + }, + }) + + err = manager.CompleteDeferredWork() + Expect(err).NotTo(HaveOccurred()) + + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: []generictables.Rule{ + { + Action: iptables.DSCPAction{Value: 20}, + Match: iptables.Match(). + SourceNet("10.0.240.3"), + }, + }, + }}}) + + By("verifying QoS policy rules removed when workload is removed") + manager.OnUpdate(&proto.WorkloadEndpointRemove{ + Id: &wlEPID2, + }) + + err = manager.CompleteDeferredWork() + Expect(err).NotTo(HaveOccurred()) + + mangleTable.checkChains([][]*generictables.Chain{{{ + Name: rules.ChainQoSPolicy, + Rules: nil, + }}}) + }) + }) +}) diff --git a/felix/fv/infrastructure/infra_k8s.go b/felix/fv/infrastructure/infra_k8s.go index 0eab20dbd93..5e59368bed4 100644 --- a/felix/fv/infrastructure/infra_k8s.go +++ b/felix/fv/infrastructure/infra_k8s.go @@ -1327,6 +1327,11 @@ func updatePodLabelsAndAnnotations(wep *libapi.WorkloadEndpoint, pod *v1.Pod) *v if pod.Annotations == nil { pod.Annotations = map[string]string{} } + if wep.Spec.QoSControls.DSCP != nil { + pod.Annotations[conversion.AnnotationQoSEgressDSCP] = wep.Spec.QoSControls.DSCP.String() + } else { + delete(pod.Annotations, conversion.AnnotationQoSEgressDSCP) + } if wep.Spec.QoSControls.IngressBandwidth != 0 { pod.Annotations[conversion.AnnotationQoSIngressBandwidth] = resource.NewQuantity(wep.Spec.QoSControls.IngressBandwidth, resource.DecimalSI).String() } else { @@ -1397,8 +1402,8 @@ func updatePodLabelsAndAnnotations(wep *libapi.WorkloadEndpoint, pod *v1.Pod) *v } else { delete(pod.Annotations, conversion.AnnotationQoSEgressMaxConnections) } - } else if pod.Annotations != nil { + delete(pod.Annotations, conversion.AnnotationQoSEgressDSCP) delete(pod.Annotations, conversion.AnnotationQoSIngressBandwidth) delete(pod.Annotations, conversion.AnnotationQoSIngressBurst) delete(pod.Annotations, conversion.AnnotationQoSIngressPeakrate) diff --git a/felix/fv/qos_policy_test.go b/felix/fv/qos_policy_test.go new file mode 100644 index 00000000000..3440bf89f4e --- /dev/null +++ b/felix/fv/qos_policy_test.go @@ -0,0 +1,394 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build fvtests + +package fv_test + +import ( + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3" + "github.com/projectcalico/api/pkg/lib/numorstring" + + "github.com/projectcalico/calico/felix/fv/connectivity" + "github.com/projectcalico/calico/felix/fv/containers" + "github.com/projectcalico/calico/felix/fv/infrastructure" + "github.com/projectcalico/calico/felix/fv/utils" + "github.com/projectcalico/calico/felix/fv/workload" + "github.com/projectcalico/calico/libcalico-go/lib/apiconfig" + api "github.com/projectcalico/calico/libcalico-go/lib/apis/v3" +) + +var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apiconfig.DatastoreType{apiconfig.EtcdV3, apiconfig.Kubernetes}, func(getInfra infrastructure.InfraFactory) { + const ( + wepPortStr = "8055" + ) + + var ( + infra infrastructure.DatastoreInfra + tc infrastructure.TopologyContainers + ep1_1, ep2_1 *workload.Workload // Workloads on Felix0 + ep1_2, ep2_2 *workload.Workload // Dual stack workloads on Felix1 + extClient *containers.Container + cc *connectivity.Checker + ) + + BeforeEach(func() { + iOpts := []infrastructure.CreateOption{} + infra = getInfra(iOpts...) + if (NFTMode() || BPFMode()) && getDataStoreType(infra) == "etcdv3" { + Skip("Skipping NFT / BPF test for etcdv3 backend.") + } + + // TODO (mazdak): Add support for bpf + if BPFMode() { + Skip("Not supported yet in bpf") + } + + options := infrastructure.DefaultTopologyOptions() + options.IPIPMode = apiv3.IPIPModeNever + options.FelixLogSeverity = "Debug" + options.EnableIPv6 = true + tc, _ = infrastructure.StartNNodeTopology(2, options, infra) + + // Install a default profile that allows all ingress and egress, in the absence of any Policy. + infra.AddDefaultAllow() + + // Create workload on host 1 (Felix0). + ep1_1 = workload.Run(tc.Felixes[0], "ep1-1", "default", "10.65.0.0", wepPortStr, "tcp") + ep1_1.ConfigureInInfra(infra) + + ep2_1 = workload.Run(tc.Felixes[0], "ep2-1", "default", "10.65.0.1", wepPortStr, "tcp") + ep2_1.ConfigureInInfra(infra) + + // Create workload on host 2 (Felix1) + ep1_2Opts := workload.WithIPv6Address("dead:beef::1:0") + ep1_2 = workload.Run(tc.Felixes[1], "ep1-2", "default", "10.65.1.0", wepPortStr, "tcp", ep1_2Opts) + ep1_2.ConfigureInInfra(infra) + + ep2_2Opts := workload.WithIPv6Address("dead:beef::1:1") + ep2_2 = workload.Run(tc.Felixes[1], "ep2-2", "default", "10.65.1.1", wepPortStr, "tcp", ep2_2Opts) + ep2_2.ConfigureInInfra(infra) + + cc = &connectivity.Checker{} + + // We will use this container to model an external client trying to connect into + // workloads on a host. Create a route in the container for the workload CIDR. + extClientOpts := infrastructure.ExtClientOpts{ + Image: utils.Config.FelixImage, + } + extClient = infrastructure.RunExtClientWithOpts("ext-client1", extClientOpts) + }) + + AfterEach(func() { + if CurrentGinkgoTestDescription().Failed { + for _, felix := range tc.Felixes { + if NFTMode() { + logNFTDiags(felix) + } else { + felix.Exec("iptables-save", "-c") + felix.Exec("ip6tables-save", "-c") + } + felix.Exec("ip", "r") + felix.Exec("ip", "-6", "r") + felix.Exec("calico-bpf", "policy", "dump", "eth0", "all", "--asm") + felix.Exec("calico-bpf", "-6", "policy", "dump", "eth0", "all", "--asm") + felix.Exec("calico-bpf", "counters", "dump") + } + } + + ep1_1.Stop() + ep2_1.Stop() + ep1_2.Stop() + ep2_2.Stop() + tc.Stop() + if CurrentGinkgoTestDescription().Failed { + infra.DumpErrorData() + } + infra.Stop() + extClient.Stop() + }) + + It("should have expected restriction on the rule jumping to QoS policy rules", func() { + detecIptablesRule := func(felix *infrastructure.Felix, ipv6 bool) { + binary := "iptables-save" + ipsetName := "cali40all-ipam-pools" + if ipv6 { + binary = "ip6tables-save" + ipsetName = "cali60all-ipam-pools" + } + expectedRule := fmt.Sprintf( + "-m set --match-set %v src -m set ! --match-set %v dst -j cali-qos-policy", ipsetName, ipsetName) + getRules := func() string { + output, _ := felix.ExecOutput(binary, "-t", "mangle") + return output + } + Eventually(getRules, 5*time.Second, 100*time.Millisecond).Should(ContainSubstring(expectedRule)) + Consistently(getRules, 5*time.Second, 100*time.Millisecond).Should(ContainSubstring(expectedRule)) + } + + detectNftablesRule := func(felix *infrastructure.Felix, ipv6 bool) { + ipsetName := "@cali40all-ipam-pools" + ipFamily := "ip" + if ipv6 { + ipsetName = "@cali60all-ipam-pools" + ipFamily = "ip6" + } + pattern := fmt.Sprintf( + "%v saddr %v %v daddr != %v .* jump mangle-cali-qos-policy", ipFamily, ipsetName, ipFamily, ipsetName) + getRules := func() string { + output, _ := felix.ExecOutput("nft", "list", "chain", ipFamily, "calico", "mangle-cali-POSTROUTING") + return output + } + Eventually(getRules, 5*time.Second, 100*time.Millisecond).Should(MatchRegexp(pattern)) + Consistently(getRules, 5*time.Second, 100*time.Millisecond).Should(MatchRegexp(pattern)) + } + + if NFTMode() { + detectNftablesRule(tc.Felixes[0], false) + detectNftablesRule(tc.Felixes[0], true) + } else { + detecIptablesRule(tc.Felixes[0], false) + detecIptablesRule(tc.Felixes[0], true) + } + }) + + It("applying DSCP annotation should result is adding correct rules", func() { + dscp0 := numorstring.DSCPFromInt(0) // 0x0 + dscp20 := numorstring.DSCPFromInt(20) // 0x14 + dscp32 := numorstring.DSCPFromInt(32) // 0x20 + dscp40 := numorstring.DSCPFromInt(40) // 0x28 + + By("configurging external client to only accept packets with specific DSCP value") + extClient.Exec("ip", "route", "add", ep1_1.IP, "via", tc.Felixes[0].IP) + extClient.Exec("ip", "route", "add", ep2_1.IP, "via", tc.Felixes[0].IP) + extClient.Exec("iptables", "-A", "INPUT", "-m", "dscp", "!", "--dscp", "0x14", "-j", "DROP") + + // Configure external client to only accept ipv4 packets with 0x14 DSCP value. + extClient.Exec("ip", "-6", "route", "add", ep1_2.IP6, "via", tc.Felixes[1].IPv6) + extClient.Exec("ip", "-6", "route", "add", ep2_2.IP6, "via", tc.Felixes[1].IPv6) + + // Configure external client to only accept ipv6 packets with 0x28 DSCP value. ICMPv6 needs to be allowed + // regardless for neighbor discovery. + extClient.Exec("ip6tables", "-A", "INPUT", "-p", "ipv6-icmp", "-j", "ACCEPT") + extClient.Exec("ip6tables", "-A", "INPUT", "-m", "dscp", "!", "--dscp", "0x28", "-j", "DROP") + + cc.ResetExpectations() + cc.ExpectNone(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + ccOpts := connectivity.ExpectWithIPVersion(6) + cc.Expect(connectivity.None, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.None, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], nil, nil) + verifyQoSPolicies(tc.Felixes[1], nil, nil) + + By("setting the initial DSCP values") + ep1_1.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp20, + } + ep1_1.UpdateInInfra(infra) + + ep2_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp40, + } + ep2_2.UpdateInInfra(infra) + + cc.ResetExpectations() + cc.ExpectSome(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.None, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.Some, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], []string{"0x14"}, nil) + verifyQoSPolicies(tc.Felixes[1], []string{"0x28"}, []string{"0x28"}) + + By("updating DSCP values on some workloads") + ep2_1.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp0, + } + ep2_1.UpdateInInfra(infra) + + ep1_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp40, + } + ep1_2.UpdateInInfra(infra) + + cc.ResetExpectations() + cc.ExpectSome(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.Some, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.Some, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], []string{"0x0", "0x14"}, nil) + verifyQoSPolicies(tc.Felixes[1], []string{"0x28", "0x28"}, []string{"0x28", "0x28"}) // 0x28 used by two workloads + + By("updating DSCP values on other workloads") + ep1_1.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp32, + } + ep1_1.UpdateInInfra(infra) + + ep1_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp20, + } + ep1_2.UpdateInInfra(infra) + + cc.ResetExpectations() + cc.ExpectNone(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.None, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.Some, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], []string{"0x0", "0x20"}, nil) + verifyQoSPolicies(tc.Felixes[1], []string{"0x14", "0x28"}, []string{"0x14", "0x28"}) + + By("reverting the DSCP values") + ep1_1.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp20, + } + ep1_1.UpdateInInfra(infra) + + ep1_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp40, + } + ep1_2.UpdateInInfra(infra) + + cc.ResetExpectations() + cc.ExpectSome(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.Some, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.Some, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], []string{"0x0", "0x14"}, nil) + verifyQoSPolicies(tc.Felixes[1], []string{"0x28", "0x28"}, []string{"0x28", "0x28"}) // 0x28 used by two workloads + By("resetting DSCP value on some workloads") + ep2_1.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{} + ep2_1.UpdateInInfra(infra) + + ep1_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{} + ep1_2.UpdateInInfra(infra) + + cc.ResetExpectations() + cc.ExpectSome(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.None, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.Some, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], []string{"0x14"}, nil) + verifyQoSPolicies(tc.Felixes[1], []string{"0x28"}, []string{"0x28"}) + + By("stopping the last workloads") + ep1_1.Stop() + ep1_1.RemoveFromInfra(infra) + + ep2_2.Stop() + ep2_2.RemoveFromInfra(infra) + + cc.ResetExpectations() + cc.ExpectNone(extClient, ep1_1) + cc.ExpectNone(extClient, ep2_1) + + cc.Expect(connectivity.None, extClient, ep1_2, ccOpts) + cc.Expect(connectivity.None, extClient, ep2_2, ccOpts) + cc.CheckConnectivity() + + verifyQoSPolicies(tc.Felixes[0], nil, nil) + verifyQoSPolicies(tc.Felixes[1], nil, nil) + }) + + It("should be able to use all DSCP string values", func() { + // We only need to run this once for iptables dataplane, and once for nftables. + if BPFMode() || getDataStoreType(infra) == "etcdv3" { + Skip("Skipping for BPF dataplane and etcdv3 backend.") + } + for dscpStr, dscpVal := range numorstring.AllDSCPValues { + // Use a workload on host2 since it's configured as dual stack. + dscp := numorstring.DSCPFromString(dscpStr) + ep1_2.WorkloadEndpoint.Spec.QoSControls = &api.QoSControls{ + DSCP: &dscp, + } + ep1_2.UpdateInInfra(infra) + + hexStr := fmt.Sprintf("0x%02x", dscpVal) + verifyQoSPolicies(tc.Felixes[1], []string{hexStr}, []string{hexStr}) + } + }) +}) + +func verifyQoSPolicies(felix *infrastructure.Felix, policies []string, policiesv6 []string) { + verifyQoSPoliciesWithIPFamily(felix, false, policies...) + verifyQoSPoliciesWithIPFamily(felix, true, policiesv6...) +} + +func verifyQoSPoliciesWithIPFamily(felix *infrastructure.Felix, ipv6 bool, values ...string) { + var ( + cmd []string + rulePattern string + ) + + assertRules := func() bool { + output, _ := felix.ExecOutput(cmd...) + if strings.Count(output, rulePattern) != len(values) { + return false + } + + for _, val := range values { + expectedRule := fmt.Sprintf("%v %v", rulePattern, val) + if !strings.Contains(output, expectedRule) { + return false + } + } + + return true + } + + if NFTMode() { + ipFamily := "ip" + if ipv6 { + ipFamily = "ip6" + } + cmd = []string{"nft", "-n", "list", "chain", ipFamily, "calico", "mangle-cali-qos-policy"} + rulePattern = fmt.Sprintf("%v dscp set", ipFamily) + } else { + binary := "iptables-save" + if ipv6 { + binary = "ip6tables-save" + } + cmd = []string{binary, "-t", "mangle"} + rulePattern = "DSCP --set-dscp" + } + + EventuallyWithOffset(1, assertRules, 5*time.Second, 100*time.Millisecond). + Should(BeTrue()) + ConsistentlyWithOffset(1, assertRules, 3*time.Second, 100*time.Millisecond). + Should(BeTrue()) +} diff --git a/felix/generictables/actions.go b/felix/generictables/actions.go index 2ef14657460..99f6b9cb809 100644 --- a/felix/generictables/actions.go +++ b/felix/generictables/actions.go @@ -35,6 +35,7 @@ type ActionFactory interface { Nflog(group uint16, prefix string, size int) Action LimitPacketRate(rate int64, burst int64, mark uint32) Action LimitNumConnections(num int64, rejectWith RejectWith) Action + DSCP(value, ipVersion uint8) Action } type RejectWith string diff --git a/felix/iptables/actions.go b/felix/iptables/actions.go index da5343b920d..a383114a1d6 100644 --- a/felix/iptables/actions.go +++ b/felix/iptables/actions.go @@ -121,6 +121,12 @@ func (a *actionFactory) LimitNumConnections(num int64, rejectWith generictables. } } +func (a *actionFactory) DSCP(value uint8, _ uint8) generictables.Action { + return DSCPAction{ + Value: value, + } +} + type Referrer interface { ReferencedChain() string } @@ -471,3 +477,15 @@ func (a LimitNumConnectionsAction) ToFragment(features *environment.Features) st func (a LimitNumConnectionsAction) String() string { return fmt.Sprintf("LimitNumConnectionsAction:%d,rejectWith:%s", a.Num, a.RejectWith) } + +type DSCPAction struct { + Value uint8 +} + +func (a DSCPAction) ToFragment(features *environment.Features) string { + return fmt.Sprintf("--jump DSCP --set-dscp %d", a.Value) +} + +func (a DSCPAction) String() string { + return fmt.Sprintf("DSCP %d", a.Value) +} diff --git a/felix/iptables/actions_test.go b/felix/iptables/actions_test.go index 7c1242aa3a0..6d77615d5ac 100644 --- a/felix/iptables/actions_test.go +++ b/felix/iptables/actions_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2022 Tigera, Inc. All rights reserved. +// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -50,4 +50,6 @@ var _ = DescribeTable("Actions", Entry("RestoreConnMarkAction", environment.Features{}, RestoreConnMarkAction{}, "--jump CONNMARK --restore-mark --mask 0xffffffff"), Entry("LimitPacketRateAction", environment.Features{}, LimitPacketRateAction{Rate: 1000, Burst: 5, Mark: 0x200}, "-m limit --limit 1000/sec --limit-burst 5 --jump MARK --set-mark 0x200/0x200"), Entry("LimitNumConnectionsAction", environment.Features{}, LimitNumConnectionsAction{Num: 10, RejectWith: generictables.RejectWithTCPReset}, "-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 10 --connlimit-mask 0 -j REJECT --reject-with tcp-reset"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 16}, "--jump DSCP --set-dscp 16"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 20}, "--jump DSCP --set-dscp 20"), ) diff --git a/felix/nftables/actions.go b/felix/nftables/actions.go index cb5d989ddda..f3f83475fbd 100644 --- a/felix/nftables/actions.go +++ b/felix/nftables/actions.go @@ -134,6 +134,13 @@ func (a *actionSet) LimitNumConnections(num int64, rejectWith generictables.Reje } } +func (a *actionSet) DSCP(value, ipVersion uint8) generictables.Action { + return DSCPAction{ + Value: value, + IpVersion: ipVersion, + } +} + func escapeLogPrefix(prefix string) string { return fmt.Sprintf("\"%s\"", prefix) } @@ -505,3 +512,19 @@ func (a LimitNumConnectionsAction) ToFragment(features *environment.Features) st func (a LimitNumConnectionsAction) String() string { return fmt.Sprintf("LimitNumConnectionsAction:%d,rejectWith:%s", a.Num, a.RejectWith) } + +type DSCPAction struct { + Value uint8 + IpVersion uint8 +} + +func (a DSCPAction) ToFragment(features *environment.Features) string { + if a.IpVersion == 6 { + return fmt.Sprintf("ip6 dscp set %d", a.Value) + } + return fmt.Sprintf("ip dscp set %d", a.Value) +} + +func (a DSCPAction) String() string { + return fmt.Sprintf("DSCP %d", a.Value) +} diff --git a/felix/nftables/actions_test.go b/felix/nftables/actions_test.go index fc6002c854d..9859a037f2e 100644 --- a/felix/nftables/actions_test.go +++ b/felix/nftables/actions_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Tigera, Inc. All rights reserved. +// Copyright (c) 2024-2025 Tigera, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -48,4 +48,6 @@ var _ = DescribeTable("Actions", Entry("SetConnMarkAction", environment.Features{}, SetConnMarkAction{Mark: 0x1000, Mask: 0xf000}, "ct mark set ct mark & 0xffff0fff ^ 0x1000"), Entry("LimitPacketRateAction", environment.Features{}, LimitPacketRateAction{Rate: 1000, Burst: 5}, "limit rate over 1000/second burst 5 packets drop"), Entry("LimitNumConnectionsAction", environment.Features{}, LimitNumConnectionsAction{Num: 10, RejectWith: generictables.RejectWithTCPReset}, "ct count over 10 reject with tcp reset"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 16, IpVersion: 4}, "ip dscp set 16"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 20, IpVersion: 6}, "ip6 dscp set 20"), ) diff --git a/felix/proto/felixbackend.pb.go b/felix/proto/felixbackend.pb.go index 5a8a6b40a37..1a66a61e46a 100644 --- a/felix/proto/felixbackend.pb.go +++ b/felix/proto/felixbackend.pb.go @@ -329,7 +329,7 @@ func (x Statistic_Direction) Number() protoreflect.EnumNumber { // Deprecated: Use Statistic_Direction.Descriptor instead. func (Statistic_Direction) EnumDescriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{68, 0} + return file_felixbackend_proto_rawDescGZIP(), []int{69, 0} } // Whether the data is relative. ABSOLUTE data gives the total for the flow @@ -378,7 +378,7 @@ func (x Statistic_Relativity) Number() protoreflect.EnumNumber { // Deprecated: Use Statistic_Relativity.Descriptor instead. func (Statistic_Relativity) EnumDescriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{68, 1} + return file_felixbackend_proto_rawDescGZIP(), []int{69, 1} } // Kind indicates what this statistic is about. @@ -425,7 +425,7 @@ func (x Statistic_Kind) Number() protoreflect.EnumNumber { // Deprecated: Use Statistic_Kind.Descriptor instead. func (Statistic_Kind) EnumDescriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{68, 2} + return file_felixbackend_proto_rawDescGZIP(), []int{69, 2} } // Whether the rule appears in INBOUND or OUTBOUND rules for the policy / @@ -473,7 +473,7 @@ func (x RuleTrace_Direction) Number() protoreflect.EnumNumber { // Deprecated: Use RuleTrace_Direction.Descriptor instead. func (RuleTrace_Direction) EnumDescriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{69, 0} + return file_felixbackend_proto_rawDescGZIP(), []int{70, 0} } type SyncRequest struct { @@ -3072,6 +3072,7 @@ type WorkloadEndpoint struct { QosControls *QoSControls `protobuf:"bytes,12,opt,name=qos_controls,json=qosControls,proto3" json:"qos_controls,omitempty"` LocalBgpPeer *LocalBGPPeer `protobuf:"bytes,13,opt,name=local_bgp_peer,json=localBgpPeer,proto3" json:"local_bgp_peer,omitempty"` SkipRedir *WorkloadBpfSkipRedir `protobuf:"bytes,14,opt,name=skip_redir,json=skipRedir,proto3" json:"skip_redir,omitempty"` + QosPolicies []*QoSPolicy `protobuf:"bytes,15,rep,name=qos_policies,json=qosPolicies,proto3" json:"qos_policies,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3204,6 +3205,13 @@ func (x *WorkloadEndpoint) GetSkipRedir() *WorkloadBpfSkipRedir { return nil } +func (x *WorkloadEndpoint) GetQosPolicies() []*QoSPolicy { + if x != nil { + return x.QosPolicies + } + return nil +} + type QoSControls struct { state protoimpl.MessageState `protogen:"open.v1"` IngressBandwidth int64 `protobuf:"varint,1,opt,name=IngressBandwidth,proto3" json:"IngressBandwidth,omitempty"` @@ -3352,6 +3360,58 @@ func (x *QoSControls) GetEgressPacketBurst() int64 { return 0 } +type QoSPolicy struct { + state protoimpl.MessageState `protogen:"open.v1"` + Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + Dscp int32 `protobuf:"varint,2,opt,name=dscp,proto3" json:"dscp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QoSPolicy) Reset() { + *x = QoSPolicy{} + mi := &file_felixbackend_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QoSPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QoSPolicy) ProtoMessage() {} + +func (x *QoSPolicy) ProtoReflect() protoreflect.Message { + mi := &file_felixbackend_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QoSPolicy.ProtoReflect.Descriptor instead. +func (*QoSPolicy) Descriptor() ([]byte, []int) { + return file_felixbackend_proto_rawDescGZIP(), []int{29} +} + +func (x *QoSPolicy) GetDestination() string { + if x != nil { + return x.Destination + } + return "" +} + +func (x *QoSPolicy) GetDscp() int32 { + if x != nil { + return x.Dscp + } + return 0 +} + type LocalBGPPeer struct { state protoimpl.MessageState `protogen:"open.v1"` BgpPeerName string `protobuf:"bytes,1,opt,name=bgp_peer_name,json=bgpPeerName,proto3" json:"bgp_peer_name,omitempty"` @@ -3361,7 +3421,7 @@ type LocalBGPPeer struct { func (x *LocalBGPPeer) Reset() { *x = LocalBGPPeer{} - mi := &file_felixbackend_proto_msgTypes[29] + mi := &file_felixbackend_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3373,7 +3433,7 @@ func (x *LocalBGPPeer) String() string { func (*LocalBGPPeer) ProtoMessage() {} func (x *LocalBGPPeer) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[29] + mi := &file_felixbackend_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3386,7 +3446,7 @@ func (x *LocalBGPPeer) ProtoReflect() protoreflect.Message { // Deprecated: Use LocalBGPPeer.ProtoReflect.Descriptor instead. func (*LocalBGPPeer) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{29} + return file_felixbackend_proto_rawDescGZIP(), []int{30} } func (x *LocalBGPPeer) GetBgpPeerName() string { @@ -3405,7 +3465,7 @@ type WorkloadEndpointRemove struct { func (x *WorkloadEndpointRemove) Reset() { *x = WorkloadEndpointRemove{} - mi := &file_felixbackend_proto_msgTypes[30] + mi := &file_felixbackend_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3417,7 +3477,7 @@ func (x *WorkloadEndpointRemove) String() string { func (*WorkloadEndpointRemove) ProtoMessage() {} func (x *WorkloadEndpointRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[30] + mi := &file_felixbackend_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3430,7 +3490,7 @@ func (x *WorkloadEndpointRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEndpointRemove.ProtoReflect.Descriptor instead. func (*WorkloadEndpointRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{30} + return file_felixbackend_proto_rawDescGZIP(), []int{31} } func (x *WorkloadEndpointRemove) GetId() *WorkloadEndpointID { @@ -3449,7 +3509,7 @@ type HostEndpointID struct { func (x *HostEndpointID) Reset() { *x = HostEndpointID{} - mi := &file_felixbackend_proto_msgTypes[31] + mi := &file_felixbackend_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3461,7 +3521,7 @@ func (x *HostEndpointID) String() string { func (*HostEndpointID) ProtoMessage() {} func (x *HostEndpointID) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[31] + mi := &file_felixbackend_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3474,7 +3534,7 @@ func (x *HostEndpointID) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpointID.ProtoReflect.Descriptor instead. func (*HostEndpointID) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{31} + return file_felixbackend_proto_rawDescGZIP(), []int{32} } func (x *HostEndpointID) GetEndpointId() string { @@ -3494,7 +3554,7 @@ type HostEndpointUpdate struct { func (x *HostEndpointUpdate) Reset() { *x = HostEndpointUpdate{} - mi := &file_felixbackend_proto_msgTypes[32] + mi := &file_felixbackend_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3506,7 +3566,7 @@ func (x *HostEndpointUpdate) String() string { func (*HostEndpointUpdate) ProtoMessage() {} func (x *HostEndpointUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[32] + mi := &file_felixbackend_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3519,7 +3579,7 @@ func (x *HostEndpointUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpointUpdate.ProtoReflect.Descriptor instead. func (*HostEndpointUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{32} + return file_felixbackend_proto_rawDescGZIP(), []int{33} } func (x *HostEndpointUpdate) GetId() *HostEndpointID { @@ -3552,7 +3612,7 @@ type HostEndpoint struct { func (x *HostEndpoint) Reset() { *x = HostEndpoint{} - mi := &file_felixbackend_proto_msgTypes[33] + mi := &file_felixbackend_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3564,7 +3624,7 @@ func (x *HostEndpoint) String() string { func (*HostEndpoint) ProtoMessage() {} func (x *HostEndpoint) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[33] + mi := &file_felixbackend_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3577,7 +3637,7 @@ func (x *HostEndpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpoint.ProtoReflect.Descriptor instead. func (*HostEndpoint) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{33} + return file_felixbackend_proto_rawDescGZIP(), []int{34} } func (x *HostEndpoint) GetName() string { @@ -3645,7 +3705,7 @@ type HostEndpointRemove struct { func (x *HostEndpointRemove) Reset() { *x = HostEndpointRemove{} - mi := &file_felixbackend_proto_msgTypes[34] + mi := &file_felixbackend_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3657,7 +3717,7 @@ func (x *HostEndpointRemove) String() string { func (*HostEndpointRemove) ProtoMessage() {} func (x *HostEndpointRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[34] + mi := &file_felixbackend_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3670,7 +3730,7 @@ func (x *HostEndpointRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpointRemove.ProtoReflect.Descriptor instead. func (*HostEndpointRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{34} + return file_felixbackend_proto_rawDescGZIP(), []int{35} } func (x *HostEndpointRemove) GetId() *HostEndpointID { @@ -3692,7 +3752,7 @@ type TierInfo struct { func (x *TierInfo) Reset() { *x = TierInfo{} - mi := &file_felixbackend_proto_msgTypes[35] + mi := &file_felixbackend_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3704,7 +3764,7 @@ func (x *TierInfo) String() string { func (*TierInfo) ProtoMessage() {} func (x *TierInfo) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[35] + mi := &file_felixbackend_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3717,7 +3777,7 @@ func (x *TierInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use TierInfo.ProtoReflect.Descriptor instead. func (*TierInfo) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{35} + return file_felixbackend_proto_rawDescGZIP(), []int{36} } func (x *TierInfo) GetName() string { @@ -3758,7 +3818,7 @@ type NatInfo struct { func (x *NatInfo) Reset() { *x = NatInfo{} - mi := &file_felixbackend_proto_msgTypes[36] + mi := &file_felixbackend_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3770,7 +3830,7 @@ func (x *NatInfo) String() string { func (*NatInfo) ProtoMessage() {} func (x *NatInfo) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[36] + mi := &file_felixbackend_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3783,7 +3843,7 @@ func (x *NatInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use NatInfo.ProtoReflect.Descriptor instead. func (*NatInfo) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{36} + return file_felixbackend_proto_rawDescGZIP(), []int{37} } func (x *NatInfo) GetExtIp() string { @@ -3810,7 +3870,7 @@ type ProcessStatusUpdate struct { func (x *ProcessStatusUpdate) Reset() { *x = ProcessStatusUpdate{} - mi := &file_felixbackend_proto_msgTypes[37] + mi := &file_felixbackend_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3822,7 +3882,7 @@ func (x *ProcessStatusUpdate) String() string { func (*ProcessStatusUpdate) ProtoMessage() {} func (x *ProcessStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[37] + mi := &file_felixbackend_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3835,7 +3895,7 @@ func (x *ProcessStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ProcessStatusUpdate.ProtoReflect.Descriptor instead. func (*ProcessStatusUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{37} + return file_felixbackend_proto_rawDescGZIP(), []int{38} } func (x *ProcessStatusUpdate) GetIsoTimestamp() string { @@ -3862,7 +3922,7 @@ type HostEndpointStatusUpdate struct { func (x *HostEndpointStatusUpdate) Reset() { *x = HostEndpointStatusUpdate{} - mi := &file_felixbackend_proto_msgTypes[38] + mi := &file_felixbackend_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3874,7 +3934,7 @@ func (x *HostEndpointStatusUpdate) String() string { func (*HostEndpointStatusUpdate) ProtoMessage() {} func (x *HostEndpointStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[38] + mi := &file_felixbackend_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3887,7 +3947,7 @@ func (x *HostEndpointStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpointStatusUpdate.ProtoReflect.Descriptor instead. func (*HostEndpointStatusUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{38} + return file_felixbackend_proto_rawDescGZIP(), []int{39} } func (x *HostEndpointStatusUpdate) GetId() *HostEndpointID { @@ -3913,7 +3973,7 @@ type EndpointStatus struct { func (x *EndpointStatus) Reset() { *x = EndpointStatus{} - mi := &file_felixbackend_proto_msgTypes[39] + mi := &file_felixbackend_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3925,7 +3985,7 @@ func (x *EndpointStatus) String() string { func (*EndpointStatus) ProtoMessage() {} func (x *EndpointStatus) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[39] + mi := &file_felixbackend_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3938,7 +3998,7 @@ func (x *EndpointStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use EndpointStatus.ProtoReflect.Descriptor instead. func (*EndpointStatus) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{39} + return file_felixbackend_proto_rawDescGZIP(), []int{40} } func (x *EndpointStatus) GetStatus() string { @@ -3957,7 +4017,7 @@ type HostEndpointStatusRemove struct { func (x *HostEndpointStatusRemove) Reset() { *x = HostEndpointStatusRemove{} - mi := &file_felixbackend_proto_msgTypes[40] + mi := &file_felixbackend_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3969,7 +4029,7 @@ func (x *HostEndpointStatusRemove) String() string { func (*HostEndpointStatusRemove) ProtoMessage() {} func (x *HostEndpointStatusRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[40] + mi := &file_felixbackend_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3982,7 +4042,7 @@ func (x *HostEndpointStatusRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use HostEndpointStatusRemove.ProtoReflect.Descriptor instead. func (*HostEndpointStatusRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{40} + return file_felixbackend_proto_rawDescGZIP(), []int{41} } func (x *HostEndpointStatusRemove) GetId() *HostEndpointID { @@ -4003,7 +4063,7 @@ type WorkloadEndpointStatusUpdate struct { func (x *WorkloadEndpointStatusUpdate) Reset() { *x = WorkloadEndpointStatusUpdate{} - mi := &file_felixbackend_proto_msgTypes[41] + mi := &file_felixbackend_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4015,7 +4075,7 @@ func (x *WorkloadEndpointStatusUpdate) String() string { func (*WorkloadEndpointStatusUpdate) ProtoMessage() {} func (x *WorkloadEndpointStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[41] + mi := &file_felixbackend_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4028,7 +4088,7 @@ func (x *WorkloadEndpointStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEndpointStatusUpdate.ProtoReflect.Descriptor instead. func (*WorkloadEndpointStatusUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{41} + return file_felixbackend_proto_rawDescGZIP(), []int{42} } func (x *WorkloadEndpointStatusUpdate) GetId() *WorkloadEndpointID { @@ -4061,7 +4121,7 @@ type WorkloadEndpointStatusRemove struct { func (x *WorkloadEndpointStatusRemove) Reset() { *x = WorkloadEndpointStatusRemove{} - mi := &file_felixbackend_proto_msgTypes[42] + mi := &file_felixbackend_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4073,7 +4133,7 @@ func (x *WorkloadEndpointStatusRemove) String() string { func (*WorkloadEndpointStatusRemove) ProtoMessage() {} func (x *WorkloadEndpointStatusRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[42] + mi := &file_felixbackend_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4086,7 +4146,7 @@ func (x *WorkloadEndpointStatusRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEndpointStatusRemove.ProtoReflect.Descriptor instead. func (*WorkloadEndpointStatusRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{42} + return file_felixbackend_proto_rawDescGZIP(), []int{43} } func (x *WorkloadEndpointStatusRemove) GetId() *WorkloadEndpointID { @@ -4108,7 +4168,7 @@ type WireguardStatusUpdate struct { func (x *WireguardStatusUpdate) Reset() { *x = WireguardStatusUpdate{} - mi := &file_felixbackend_proto_msgTypes[43] + mi := &file_felixbackend_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4120,7 +4180,7 @@ func (x *WireguardStatusUpdate) String() string { func (*WireguardStatusUpdate) ProtoMessage() {} func (x *WireguardStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[43] + mi := &file_felixbackend_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4133,7 +4193,7 @@ func (x *WireguardStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use WireguardStatusUpdate.ProtoReflect.Descriptor instead. func (*WireguardStatusUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{43} + return file_felixbackend_proto_rawDescGZIP(), []int{44} } func (x *WireguardStatusUpdate) GetPublicKey() string { @@ -4158,7 +4218,7 @@ type DataplaneInSync struct { func (x *DataplaneInSync) Reset() { *x = DataplaneInSync{} - mi := &file_felixbackend_proto_msgTypes[44] + mi := &file_felixbackend_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4170,7 +4230,7 @@ func (x *DataplaneInSync) String() string { func (*DataplaneInSync) ProtoMessage() {} func (x *DataplaneInSync) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[44] + mi := &file_felixbackend_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4183,7 +4243,7 @@ func (x *DataplaneInSync) ProtoReflect() protoreflect.Message { // Deprecated: Use DataplaneInSync.ProtoReflect.Descriptor instead. func (*DataplaneInSync) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{44} + return file_felixbackend_proto_rawDescGZIP(), []int{45} } type HostMetadataV4V6Update struct { @@ -4199,7 +4259,7 @@ type HostMetadataV4V6Update struct { func (x *HostMetadataV4V6Update) Reset() { *x = HostMetadataV4V6Update{} - mi := &file_felixbackend_proto_msgTypes[45] + mi := &file_felixbackend_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4211,7 +4271,7 @@ func (x *HostMetadataV4V6Update) String() string { func (*HostMetadataV4V6Update) ProtoMessage() {} func (x *HostMetadataV4V6Update) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[45] + mi := &file_felixbackend_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4224,7 +4284,7 @@ func (x *HostMetadataV4V6Update) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataV4V6Update.ProtoReflect.Descriptor instead. func (*HostMetadataV4V6Update) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{45} + return file_felixbackend_proto_rawDescGZIP(), []int{46} } func (x *HostMetadataV4V6Update) GetHostname() string { @@ -4272,7 +4332,7 @@ type HostMetadataV4V6Remove struct { func (x *HostMetadataV4V6Remove) Reset() { *x = HostMetadataV4V6Remove{} - mi := &file_felixbackend_proto_msgTypes[46] + mi := &file_felixbackend_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4284,7 +4344,7 @@ func (x *HostMetadataV4V6Remove) String() string { func (*HostMetadataV4V6Remove) ProtoMessage() {} func (x *HostMetadataV4V6Remove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[46] + mi := &file_felixbackend_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4297,7 +4357,7 @@ func (x *HostMetadataV4V6Remove) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataV4V6Remove.ProtoReflect.Descriptor instead. func (*HostMetadataV4V6Remove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{46} + return file_felixbackend_proto_rawDescGZIP(), []int{47} } func (x *HostMetadataV4V6Remove) GetHostname() string { @@ -4324,7 +4384,7 @@ type HostMetadataUpdate struct { func (x *HostMetadataUpdate) Reset() { *x = HostMetadataUpdate{} - mi := &file_felixbackend_proto_msgTypes[47] + mi := &file_felixbackend_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4336,7 +4396,7 @@ func (x *HostMetadataUpdate) String() string { func (*HostMetadataUpdate) ProtoMessage() {} func (x *HostMetadataUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[47] + mi := &file_felixbackend_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4349,7 +4409,7 @@ func (x *HostMetadataUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataUpdate.ProtoReflect.Descriptor instead. func (*HostMetadataUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{47} + return file_felixbackend_proto_rawDescGZIP(), []int{48} } func (x *HostMetadataUpdate) GetHostname() string { @@ -4376,7 +4436,7 @@ type HostMetadataRemove struct { func (x *HostMetadataRemove) Reset() { *x = HostMetadataRemove{} - mi := &file_felixbackend_proto_msgTypes[48] + mi := &file_felixbackend_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4388,7 +4448,7 @@ func (x *HostMetadataRemove) String() string { func (*HostMetadataRemove) ProtoMessage() {} func (x *HostMetadataRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[48] + mi := &file_felixbackend_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4401,7 +4461,7 @@ func (x *HostMetadataRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataRemove.ProtoReflect.Descriptor instead. func (*HostMetadataRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{48} + return file_felixbackend_proto_rawDescGZIP(), []int{49} } func (x *HostMetadataRemove) GetHostname() string { @@ -4428,7 +4488,7 @@ type HostMetadataV6Update struct { func (x *HostMetadataV6Update) Reset() { *x = HostMetadataV6Update{} - mi := &file_felixbackend_proto_msgTypes[49] + mi := &file_felixbackend_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4440,7 +4500,7 @@ func (x *HostMetadataV6Update) String() string { func (*HostMetadataV6Update) ProtoMessage() {} func (x *HostMetadataV6Update) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[49] + mi := &file_felixbackend_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4453,7 +4513,7 @@ func (x *HostMetadataV6Update) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataV6Update.ProtoReflect.Descriptor instead. func (*HostMetadataV6Update) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{49} + return file_felixbackend_proto_rawDescGZIP(), []int{50} } func (x *HostMetadataV6Update) GetHostname() string { @@ -4480,7 +4540,7 @@ type HostMetadataV6Remove struct { func (x *HostMetadataV6Remove) Reset() { *x = HostMetadataV6Remove{} - mi := &file_felixbackend_proto_msgTypes[50] + mi := &file_felixbackend_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4492,7 +4552,7 @@ func (x *HostMetadataV6Remove) String() string { func (*HostMetadataV6Remove) ProtoMessage() {} func (x *HostMetadataV6Remove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[50] + mi := &file_felixbackend_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4505,7 +4565,7 @@ func (x *HostMetadataV6Remove) ProtoReflect() protoreflect.Message { // Deprecated: Use HostMetadataV6Remove.ProtoReflect.Descriptor instead. func (*HostMetadataV6Remove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{50} + return file_felixbackend_proto_rawDescGZIP(), []int{51} } func (x *HostMetadataV6Remove) GetHostname() string { @@ -4532,7 +4592,7 @@ type IPAMPoolUpdate struct { func (x *IPAMPoolUpdate) Reset() { *x = IPAMPoolUpdate{} - mi := &file_felixbackend_proto_msgTypes[51] + mi := &file_felixbackend_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4544,7 +4604,7 @@ func (x *IPAMPoolUpdate) String() string { func (*IPAMPoolUpdate) ProtoMessage() {} func (x *IPAMPoolUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[51] + mi := &file_felixbackend_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4557,7 +4617,7 @@ func (x *IPAMPoolUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use IPAMPoolUpdate.ProtoReflect.Descriptor instead. func (*IPAMPoolUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{51} + return file_felixbackend_proto_rawDescGZIP(), []int{52} } func (x *IPAMPoolUpdate) GetId() string { @@ -4583,7 +4643,7 @@ type IPAMPoolRemove struct { func (x *IPAMPoolRemove) Reset() { *x = IPAMPoolRemove{} - mi := &file_felixbackend_proto_msgTypes[52] + mi := &file_felixbackend_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4595,7 +4655,7 @@ func (x *IPAMPoolRemove) String() string { func (*IPAMPoolRemove) ProtoMessage() {} func (x *IPAMPoolRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[52] + mi := &file_felixbackend_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4608,7 +4668,7 @@ func (x *IPAMPoolRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use IPAMPoolRemove.ProtoReflect.Descriptor instead. func (*IPAMPoolRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{52} + return file_felixbackend_proto_rawDescGZIP(), []int{53} } func (x *IPAMPoolRemove) GetId() string { @@ -4630,7 +4690,7 @@ type IPAMPool struct { func (x *IPAMPool) Reset() { *x = IPAMPool{} - mi := &file_felixbackend_proto_msgTypes[53] + mi := &file_felixbackend_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4642,7 +4702,7 @@ func (x *IPAMPool) String() string { func (*IPAMPool) ProtoMessage() {} func (x *IPAMPool) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[53] + mi := &file_felixbackend_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4655,7 +4715,7 @@ func (x *IPAMPool) ProtoReflect() protoreflect.Message { // Deprecated: Use IPAMPool.ProtoReflect.Descriptor instead. func (*IPAMPool) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{53} + return file_felixbackend_proto_rawDescGZIP(), []int{54} } func (x *IPAMPool) GetCidr() string { @@ -4697,7 +4757,7 @@ type Encapsulation struct { func (x *Encapsulation) Reset() { *x = Encapsulation{} - mi := &file_felixbackend_proto_msgTypes[54] + mi := &file_felixbackend_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4709,7 +4769,7 @@ func (x *Encapsulation) String() string { func (*Encapsulation) ProtoMessage() {} func (x *Encapsulation) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[54] + mi := &file_felixbackend_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4722,7 +4782,7 @@ func (x *Encapsulation) ProtoReflect() protoreflect.Message { // Deprecated: Use Encapsulation.ProtoReflect.Descriptor instead. func (*Encapsulation) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{54} + return file_felixbackend_proto_rawDescGZIP(), []int{55} } func (x *Encapsulation) GetIpipEnabled() bool { @@ -4756,7 +4816,7 @@ type ServiceAccountUpdate struct { func (x *ServiceAccountUpdate) Reset() { *x = ServiceAccountUpdate{} - mi := &file_felixbackend_proto_msgTypes[55] + mi := &file_felixbackend_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4768,7 +4828,7 @@ func (x *ServiceAccountUpdate) String() string { func (*ServiceAccountUpdate) ProtoMessage() {} func (x *ServiceAccountUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[55] + mi := &file_felixbackend_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4781,7 +4841,7 @@ func (x *ServiceAccountUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceAccountUpdate.ProtoReflect.Descriptor instead. func (*ServiceAccountUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{55} + return file_felixbackend_proto_rawDescGZIP(), []int{56} } func (x *ServiceAccountUpdate) GetId() *ServiceAccountID { @@ -4807,7 +4867,7 @@ type ServiceAccountRemove struct { func (x *ServiceAccountRemove) Reset() { *x = ServiceAccountRemove{} - mi := &file_felixbackend_proto_msgTypes[56] + mi := &file_felixbackend_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4819,7 +4879,7 @@ func (x *ServiceAccountRemove) String() string { func (*ServiceAccountRemove) ProtoMessage() {} func (x *ServiceAccountRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[56] + mi := &file_felixbackend_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4832,7 +4892,7 @@ func (x *ServiceAccountRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceAccountRemove.ProtoReflect.Descriptor instead. func (*ServiceAccountRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{56} + return file_felixbackend_proto_rawDescGZIP(), []int{57} } func (x *ServiceAccountRemove) GetId() *ServiceAccountID { @@ -4852,7 +4912,7 @@ type ServiceAccountID struct { func (x *ServiceAccountID) Reset() { *x = ServiceAccountID{} - mi := &file_felixbackend_proto_msgTypes[57] + mi := &file_felixbackend_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4864,7 +4924,7 @@ func (x *ServiceAccountID) String() string { func (*ServiceAccountID) ProtoMessage() {} func (x *ServiceAccountID) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[57] + mi := &file_felixbackend_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4877,7 +4937,7 @@ func (x *ServiceAccountID) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceAccountID.ProtoReflect.Descriptor instead. func (*ServiceAccountID) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{57} + return file_felixbackend_proto_rawDescGZIP(), []int{58} } func (x *ServiceAccountID) GetNamespace() string { @@ -4904,7 +4964,7 @@ type NamespaceUpdate struct { func (x *NamespaceUpdate) Reset() { *x = NamespaceUpdate{} - mi := &file_felixbackend_proto_msgTypes[58] + mi := &file_felixbackend_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4916,7 +4976,7 @@ func (x *NamespaceUpdate) String() string { func (*NamespaceUpdate) ProtoMessage() {} func (x *NamespaceUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[58] + mi := &file_felixbackend_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4929,7 +4989,7 @@ func (x *NamespaceUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use NamespaceUpdate.ProtoReflect.Descriptor instead. func (*NamespaceUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{58} + return file_felixbackend_proto_rawDescGZIP(), []int{59} } func (x *NamespaceUpdate) GetId() *NamespaceID { @@ -4955,7 +5015,7 @@ type NamespaceRemove struct { func (x *NamespaceRemove) Reset() { *x = NamespaceRemove{} - mi := &file_felixbackend_proto_msgTypes[59] + mi := &file_felixbackend_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4967,7 +5027,7 @@ func (x *NamespaceRemove) String() string { func (*NamespaceRemove) ProtoMessage() {} func (x *NamespaceRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[59] + mi := &file_felixbackend_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4980,7 +5040,7 @@ func (x *NamespaceRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use NamespaceRemove.ProtoReflect.Descriptor instead. func (*NamespaceRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{59} + return file_felixbackend_proto_rawDescGZIP(), []int{60} } func (x *NamespaceRemove) GetId() *NamespaceID { @@ -4999,7 +5059,7 @@ type NamespaceID struct { func (x *NamespaceID) Reset() { *x = NamespaceID{} - mi := &file_felixbackend_proto_msgTypes[60] + mi := &file_felixbackend_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5011,7 +5071,7 @@ func (x *NamespaceID) String() string { func (*NamespaceID) ProtoMessage() {} func (x *NamespaceID) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[60] + mi := &file_felixbackend_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5024,7 +5084,7 @@ func (x *NamespaceID) ProtoReflect() protoreflect.Message { // Deprecated: Use NamespaceID.ProtoReflect.Descriptor instead. func (*NamespaceID) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{60} + return file_felixbackend_proto_rawDescGZIP(), []int{61} } func (x *NamespaceID) GetName() string { @@ -5045,7 +5105,7 @@ type TunnelType struct { func (x *TunnelType) Reset() { *x = TunnelType{} - mi := &file_felixbackend_proto_msgTypes[61] + mi := &file_felixbackend_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5057,7 +5117,7 @@ func (x *TunnelType) String() string { func (*TunnelType) ProtoMessage() {} func (x *TunnelType) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[61] + mi := &file_felixbackend_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5070,7 +5130,7 @@ func (x *TunnelType) ProtoReflect() protoreflect.Message { // Deprecated: Use TunnelType.ProtoReflect.Descriptor instead. func (*TunnelType) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{61} + return file_felixbackend_proto_rawDescGZIP(), []int{62} } func (x *TunnelType) GetIpip() bool { @@ -5115,7 +5175,7 @@ type RouteUpdate struct { func (x *RouteUpdate) Reset() { *x = RouteUpdate{} - mi := &file_felixbackend_proto_msgTypes[62] + mi := &file_felixbackend_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5127,7 +5187,7 @@ func (x *RouteUpdate) String() string { func (*RouteUpdate) ProtoMessage() {} func (x *RouteUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[62] + mi := &file_felixbackend_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5140,7 +5200,7 @@ func (x *RouteUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use RouteUpdate.ProtoReflect.Descriptor instead. func (*RouteUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{62} + return file_felixbackend_proto_rawDescGZIP(), []int{63} } func (x *RouteUpdate) GetTypes() RouteType { @@ -5222,7 +5282,7 @@ type RouteRemove struct { func (x *RouteRemove) Reset() { *x = RouteRemove{} - mi := &file_felixbackend_proto_msgTypes[63] + mi := &file_felixbackend_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5234,7 +5294,7 @@ func (x *RouteRemove) String() string { func (*RouteRemove) ProtoMessage() {} func (x *RouteRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[63] + mi := &file_felixbackend_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5247,7 +5307,7 @@ func (x *RouteRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use RouteRemove.ProtoReflect.Descriptor instead. func (*RouteRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{63} + return file_felixbackend_proto_rawDescGZIP(), []int{64} } func (x *RouteRemove) GetDst() string { @@ -5272,7 +5332,7 @@ type VXLANTunnelEndpointUpdate struct { func (x *VXLANTunnelEndpointUpdate) Reset() { *x = VXLANTunnelEndpointUpdate{} - mi := &file_felixbackend_proto_msgTypes[64] + mi := &file_felixbackend_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5284,7 +5344,7 @@ func (x *VXLANTunnelEndpointUpdate) String() string { func (*VXLANTunnelEndpointUpdate) ProtoMessage() {} func (x *VXLANTunnelEndpointUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[64] + mi := &file_felixbackend_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5297,7 +5357,7 @@ func (x *VXLANTunnelEndpointUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use VXLANTunnelEndpointUpdate.ProtoReflect.Descriptor instead. func (*VXLANTunnelEndpointUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{64} + return file_felixbackend_proto_rawDescGZIP(), []int{65} } func (x *VXLANTunnelEndpointUpdate) GetNode() string { @@ -5358,7 +5418,7 @@ type VXLANTunnelEndpointRemove struct { func (x *VXLANTunnelEndpointRemove) Reset() { *x = VXLANTunnelEndpointRemove{} - mi := &file_felixbackend_proto_msgTypes[65] + mi := &file_felixbackend_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5370,7 +5430,7 @@ func (x *VXLANTunnelEndpointRemove) String() string { func (*VXLANTunnelEndpointRemove) ProtoMessage() {} func (x *VXLANTunnelEndpointRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[65] + mi := &file_felixbackend_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5383,7 +5443,7 @@ func (x *VXLANTunnelEndpointRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use VXLANTunnelEndpointRemove.ProtoReflect.Descriptor instead. func (*VXLANTunnelEndpointRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{65} + return file_felixbackend_proto_rawDescGZIP(), []int{66} } func (x *VXLANTunnelEndpointRemove) GetNode() string { @@ -5403,7 +5463,7 @@ type ReportResult struct { func (x *ReportResult) Reset() { *x = ReportResult{} - mi := &file_felixbackend_proto_msgTypes[66] + mi := &file_felixbackend_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5415,7 +5475,7 @@ func (x *ReportResult) String() string { func (*ReportResult) ProtoMessage() {} func (x *ReportResult) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[66] + mi := &file_felixbackend_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5428,7 +5488,7 @@ func (x *ReportResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportResult.ProtoReflect.Descriptor instead. func (*ReportResult) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{66} + return file_felixbackend_proto_rawDescGZIP(), []int{67} } func (x *ReportResult) GetSuccessful() bool { @@ -5462,7 +5522,7 @@ type DataplaneStats struct { func (x *DataplaneStats) Reset() { *x = DataplaneStats{} - mi := &file_felixbackend_proto_msgTypes[67] + mi := &file_felixbackend_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5474,7 +5534,7 @@ func (x *DataplaneStats) String() string { func (*DataplaneStats) ProtoMessage() {} func (x *DataplaneStats) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[67] + mi := &file_felixbackend_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5487,7 +5547,7 @@ func (x *DataplaneStats) ProtoReflect() protoreflect.Message { // Deprecated: Use DataplaneStats.ProtoReflect.Descriptor instead. func (*DataplaneStats) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{67} + return file_felixbackend_proto_rawDescGZIP(), []int{68} } func (x *DataplaneStats) GetSrcIp() string { @@ -5563,7 +5623,7 @@ type Statistic struct { func (x *Statistic) Reset() { *x = Statistic{} - mi := &file_felixbackend_proto_msgTypes[68] + mi := &file_felixbackend_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5575,7 +5635,7 @@ func (x *Statistic) String() string { func (*Statistic) ProtoMessage() {} func (x *Statistic) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[68] + mi := &file_felixbackend_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5588,7 +5648,7 @@ func (x *Statistic) ProtoReflect() protoreflect.Message { // Deprecated: Use Statistic.ProtoReflect.Descriptor instead. func (*Statistic) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{68} + return file_felixbackend_proto_rawDescGZIP(), []int{69} } func (x *Statistic) GetDirection() Statistic_Direction { @@ -5644,7 +5704,7 @@ type RuleTrace struct { func (x *RuleTrace) Reset() { *x = RuleTrace{} - mi := &file_felixbackend_proto_msgTypes[69] + mi := &file_felixbackend_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5656,7 +5716,7 @@ func (x *RuleTrace) String() string { func (*RuleTrace) ProtoMessage() {} func (x *RuleTrace) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[69] + mi := &file_felixbackend_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5669,7 +5729,7 @@ func (x *RuleTrace) ProtoReflect() protoreflect.Message { // Deprecated: Use RuleTrace.ProtoReflect.Descriptor instead. func (*RuleTrace) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{69} + return file_felixbackend_proto_rawDescGZIP(), []int{70} } func (x *RuleTrace) GetId() isRuleTrace_Id { @@ -5761,7 +5821,7 @@ type WireguardEndpointUpdate struct { func (x *WireguardEndpointUpdate) Reset() { *x = WireguardEndpointUpdate{} - mi := &file_felixbackend_proto_msgTypes[70] + mi := &file_felixbackend_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5773,7 +5833,7 @@ func (x *WireguardEndpointUpdate) String() string { func (*WireguardEndpointUpdate) ProtoMessage() {} func (x *WireguardEndpointUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[70] + mi := &file_felixbackend_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5786,7 +5846,7 @@ func (x *WireguardEndpointUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use WireguardEndpointUpdate.ProtoReflect.Descriptor instead. func (*WireguardEndpointUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{70} + return file_felixbackend_proto_rawDescGZIP(), []int{71} } func (x *WireguardEndpointUpdate) GetHostname() string { @@ -5820,7 +5880,7 @@ type WireguardEndpointRemove struct { func (x *WireguardEndpointRemove) Reset() { *x = WireguardEndpointRemove{} - mi := &file_felixbackend_proto_msgTypes[71] + mi := &file_felixbackend_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5832,7 +5892,7 @@ func (x *WireguardEndpointRemove) String() string { func (*WireguardEndpointRemove) ProtoMessage() {} func (x *WireguardEndpointRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[71] + mi := &file_felixbackend_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5845,7 +5905,7 @@ func (x *WireguardEndpointRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use WireguardEndpointRemove.ProtoReflect.Descriptor instead. func (*WireguardEndpointRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{71} + return file_felixbackend_proto_rawDescGZIP(), []int{72} } func (x *WireguardEndpointRemove) GetHostname() string { @@ -5869,7 +5929,7 @@ type WireguardEndpointV6Update struct { func (x *WireguardEndpointV6Update) Reset() { *x = WireguardEndpointV6Update{} - mi := &file_felixbackend_proto_msgTypes[72] + mi := &file_felixbackend_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5881,7 +5941,7 @@ func (x *WireguardEndpointV6Update) String() string { func (*WireguardEndpointV6Update) ProtoMessage() {} func (x *WireguardEndpointV6Update) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[72] + mi := &file_felixbackend_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5894,7 +5954,7 @@ func (x *WireguardEndpointV6Update) ProtoReflect() protoreflect.Message { // Deprecated: Use WireguardEndpointV6Update.ProtoReflect.Descriptor instead. func (*WireguardEndpointV6Update) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{72} + return file_felixbackend_proto_rawDescGZIP(), []int{73} } func (x *WireguardEndpointV6Update) GetHostname() string { @@ -5928,7 +5988,7 @@ type WireguardEndpointV6Remove struct { func (x *WireguardEndpointV6Remove) Reset() { *x = WireguardEndpointV6Remove{} - mi := &file_felixbackend_proto_msgTypes[73] + mi := &file_felixbackend_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5940,7 +6000,7 @@ func (x *WireguardEndpointV6Remove) String() string { func (*WireguardEndpointV6Remove) ProtoMessage() {} func (x *WireguardEndpointV6Remove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[73] + mi := &file_felixbackend_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5953,7 +6013,7 @@ func (x *WireguardEndpointV6Remove) ProtoReflect() protoreflect.Message { // Deprecated: Use WireguardEndpointV6Remove.ProtoReflect.Descriptor instead. func (*WireguardEndpointV6Remove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{73} + return file_felixbackend_proto_rawDescGZIP(), []int{74} } func (x *WireguardEndpointV6Remove) GetHostname() string { @@ -5976,7 +6036,7 @@ type GlobalBGPConfigUpdate struct { func (x *GlobalBGPConfigUpdate) Reset() { *x = GlobalBGPConfigUpdate{} - mi := &file_felixbackend_proto_msgTypes[74] + mi := &file_felixbackend_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5988,7 +6048,7 @@ func (x *GlobalBGPConfigUpdate) String() string { func (*GlobalBGPConfigUpdate) ProtoMessage() {} func (x *GlobalBGPConfigUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[74] + mi := &file_felixbackend_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6001,7 +6061,7 @@ func (x *GlobalBGPConfigUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GlobalBGPConfigUpdate.ProtoReflect.Descriptor instead. func (*GlobalBGPConfigUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{74} + return file_felixbackend_proto_rawDescGZIP(), []int{75} } func (x *GlobalBGPConfigUpdate) GetServiceClusterCidrs() []string { @@ -6050,7 +6110,7 @@ type ServicePort struct { func (x *ServicePort) Reset() { *x = ServicePort{} - mi := &file_felixbackend_proto_msgTypes[75] + mi := &file_felixbackend_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6062,7 +6122,7 @@ func (x *ServicePort) String() string { func (*ServicePort) ProtoMessage() {} func (x *ServicePort) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[75] + mi := &file_felixbackend_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6075,7 +6135,7 @@ func (x *ServicePort) ProtoReflect() protoreflect.Message { // Deprecated: Use ServicePort.ProtoReflect.Descriptor instead. func (*ServicePort) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{75} + return file_felixbackend_proto_rawDescGZIP(), []int{76} } func (x *ServicePort) GetProtocol() string { @@ -6114,7 +6174,7 @@ type ServiceUpdate struct { func (x *ServiceUpdate) Reset() { *x = ServiceUpdate{} - mi := &file_felixbackend_proto_msgTypes[76] + mi := &file_felixbackend_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6126,7 +6186,7 @@ func (x *ServiceUpdate) String() string { func (*ServiceUpdate) ProtoMessage() {} func (x *ServiceUpdate) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[76] + mi := &file_felixbackend_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6139,7 +6199,7 @@ func (x *ServiceUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceUpdate.ProtoReflect.Descriptor instead. func (*ServiceUpdate) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{76} + return file_felixbackend_proto_rawDescGZIP(), []int{77} } func (x *ServiceUpdate) GetName() string { @@ -6201,7 +6261,7 @@ type ServiceRemove struct { func (x *ServiceRemove) Reset() { *x = ServiceRemove{} - mi := &file_felixbackend_proto_msgTypes[77] + mi := &file_felixbackend_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6213,7 +6273,7 @@ func (x *ServiceRemove) String() string { func (*ServiceRemove) ProtoMessage() {} func (x *ServiceRemove) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[77] + mi := &file_felixbackend_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6226,7 +6286,7 @@ func (x *ServiceRemove) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceRemove.ProtoReflect.Descriptor instead. func (*ServiceRemove) Descriptor() ([]byte, []int) { - return file_felixbackend_proto_rawDescGZIP(), []int{77} + return file_felixbackend_proto_rawDescGZIP(), []int{78} } func (x *ServiceRemove) GetName() string { @@ -6256,7 +6316,7 @@ type HTTPMatch_PathMatch struct { func (x *HTTPMatch_PathMatch) Reset() { *x = HTTPMatch_PathMatch{} - mi := &file_felixbackend_proto_msgTypes[81] + mi := &file_felixbackend_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6268,7 +6328,7 @@ func (x *HTTPMatch_PathMatch) String() string { func (*HTTPMatch_PathMatch) ProtoMessage() {} func (x *HTTPMatch_PathMatch) ProtoReflect() protoreflect.Message { - mi := &file_felixbackend_proto_msgTypes[81] + mi := &file_felixbackend_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6526,7 +6586,7 @@ const file_felixbackend_proto_rawDesc = "" + "\bendpoint\x18\x05 \x01(\v2\x17.felix.WorkloadEndpointR\bendpoint\"H\n" + "\x14WorkloadBpfSkipRedir\x12\x16\n" + "\x06Egress\x18\x01 \x01(\bR\x06Egress\x12\x18\n" + - "\aIngress\x18\x02 \x01(\bR\aIngress\"\xa3\x05\n" + + "\aIngress\x18\x02 \x01(\bR\aIngress\"\xd8\x05\n" + "\x10WorkloadEndpoint\x12\x14\n" + "\x05state\x18\x01 \x01(\tR\x05state\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x10\n" + @@ -6544,7 +6604,8 @@ const file_felixbackend_proto_rawDesc = "" + "\fqos_controls\x18\f \x01(\v2\x12.felix.QoSControlsR\vqosControls\x129\n" + "\x0elocal_bgp_peer\x18\r \x01(\v2\x13.felix.LocalBGPPeerR\flocalBgpPeer\x12:\n" + "\n" + - "skip_redir\x18\x0e \x01(\v2\x1b.felix.WorkloadBpfSkipRedirR\tskipRedir\x1a>\n" + + "skip_redir\x18\x0e \x01(\v2\x1b.felix.WorkloadBpfSkipRedirR\tskipRedir\x123\n" + + "\fqos_policies\x18\x0f \x03(\v2\x10.felix.QoSPolicyR\vqosPolicies\x1a>\n" + "\x10AnnotationsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xef\x04\n" + @@ -6563,7 +6624,10 @@ const file_felixbackend_proto_rawDesc = "" + "\x0fIngressMinburst\x18\v \x01(\x03R\x0fIngressMinburst\x12&\n" + "\x0eEgressMinburst\x18\f \x01(\x03R\x0eEgressMinburst\x12.\n" + "\x12IngressPacketBurst\x18\r \x01(\x03R\x12IngressPacketBurst\x12,\n" + - "\x11EgressPacketBurst\x18\x0e \x01(\x03R\x11EgressPacketBurst\"2\n" + + "\x11EgressPacketBurst\x18\x0e \x01(\x03R\x11EgressPacketBurst\"A\n" + + "\tQoSPolicy\x12 \n" + + "\vdestination\x18\x01 \x01(\tR\vdestination\x12\x12\n" + + "\x04dscp\x18\x02 \x01(\x05R\x04dscp\"2\n" + "\fLocalBGPPeer\x12\"\n" + "\rbgp_peer_name\x18\x01 \x01(\tR\vbgpPeerName\"C\n" + "\x16WorkloadEndpointRemove\x12)\n" + @@ -6827,7 +6891,7 @@ func file_felixbackend_proto_rawDescGZIP() []byte { } var file_felixbackend_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_felixbackend_proto_msgTypes = make([]protoimpl.MessageInfo, 87) +var file_felixbackend_proto_msgTypes = make([]protoimpl.MessageInfo, 88) var file_felixbackend_proto_goTypes = []any{ (IPVersion)(0), // 0: felix.IPVersion (RouteType)(0), // 1: felix.RouteType @@ -6867,64 +6931,65 @@ var file_felixbackend_proto_goTypes = []any{ (*WorkloadBpfSkipRedir)(nil), // 35: felix.WorkloadBpfSkipRedir (*WorkloadEndpoint)(nil), // 36: felix.WorkloadEndpoint (*QoSControls)(nil), // 37: felix.QoSControls - (*LocalBGPPeer)(nil), // 38: felix.LocalBGPPeer - (*WorkloadEndpointRemove)(nil), // 39: felix.WorkloadEndpointRemove - (*HostEndpointID)(nil), // 40: felix.HostEndpointID - (*HostEndpointUpdate)(nil), // 41: felix.HostEndpointUpdate - (*HostEndpoint)(nil), // 42: felix.HostEndpoint - (*HostEndpointRemove)(nil), // 43: felix.HostEndpointRemove - (*TierInfo)(nil), // 44: felix.TierInfo - (*NatInfo)(nil), // 45: felix.NatInfo - (*ProcessStatusUpdate)(nil), // 46: felix.ProcessStatusUpdate - (*HostEndpointStatusUpdate)(nil), // 47: felix.HostEndpointStatusUpdate - (*EndpointStatus)(nil), // 48: felix.EndpointStatus - (*HostEndpointStatusRemove)(nil), // 49: felix.HostEndpointStatusRemove - (*WorkloadEndpointStatusUpdate)(nil), // 50: felix.WorkloadEndpointStatusUpdate - (*WorkloadEndpointStatusRemove)(nil), // 51: felix.WorkloadEndpointStatusRemove - (*WireguardStatusUpdate)(nil), // 52: felix.WireguardStatusUpdate - (*DataplaneInSync)(nil), // 53: felix.DataplaneInSync - (*HostMetadataV4V6Update)(nil), // 54: felix.HostMetadataV4V6Update - (*HostMetadataV4V6Remove)(nil), // 55: felix.HostMetadataV4V6Remove - (*HostMetadataUpdate)(nil), // 56: felix.HostMetadataUpdate - (*HostMetadataRemove)(nil), // 57: felix.HostMetadataRemove - (*HostMetadataV6Update)(nil), // 58: felix.HostMetadataV6Update - (*HostMetadataV6Remove)(nil), // 59: felix.HostMetadataV6Remove - (*IPAMPoolUpdate)(nil), // 60: felix.IPAMPoolUpdate - (*IPAMPoolRemove)(nil), // 61: felix.IPAMPoolRemove - (*IPAMPool)(nil), // 62: felix.IPAMPool - (*Encapsulation)(nil), // 63: felix.Encapsulation - (*ServiceAccountUpdate)(nil), // 64: felix.ServiceAccountUpdate - (*ServiceAccountRemove)(nil), // 65: felix.ServiceAccountRemove - (*ServiceAccountID)(nil), // 66: felix.ServiceAccountID - (*NamespaceUpdate)(nil), // 67: felix.NamespaceUpdate - (*NamespaceRemove)(nil), // 68: felix.NamespaceRemove - (*NamespaceID)(nil), // 69: felix.NamespaceID - (*TunnelType)(nil), // 70: felix.TunnelType - (*RouteUpdate)(nil), // 71: felix.RouteUpdate - (*RouteRemove)(nil), // 72: felix.RouteRemove - (*VXLANTunnelEndpointUpdate)(nil), // 73: felix.VXLANTunnelEndpointUpdate - (*VXLANTunnelEndpointRemove)(nil), // 74: felix.VXLANTunnelEndpointRemove - (*ReportResult)(nil), // 75: felix.ReportResult - (*DataplaneStats)(nil), // 76: felix.DataplaneStats - (*Statistic)(nil), // 77: felix.Statistic - (*RuleTrace)(nil), // 78: felix.RuleTrace - (*WireguardEndpointUpdate)(nil), // 79: felix.WireguardEndpointUpdate - (*WireguardEndpointRemove)(nil), // 80: felix.WireguardEndpointRemove - (*WireguardEndpointV6Update)(nil), // 81: felix.WireguardEndpointV6Update - (*WireguardEndpointV6Remove)(nil), // 82: felix.WireguardEndpointV6Remove - (*GlobalBGPConfigUpdate)(nil), // 83: felix.GlobalBGPConfigUpdate - (*ServicePort)(nil), // 84: felix.ServicePort - (*ServiceUpdate)(nil), // 85: felix.ServiceUpdate - (*ServiceRemove)(nil), // 86: felix.ServiceRemove - nil, // 87: felix.ConfigUpdate.ConfigEntry - nil, // 88: felix.ConfigUpdate.SourceToRawConfigEntry - nil, // 89: felix.RawConfig.ConfigEntry - (*HTTPMatch_PathMatch)(nil), // 90: felix.HTTPMatch.PathMatch - nil, // 91: felix.RuleMetadata.AnnotationsEntry - nil, // 92: felix.WorkloadEndpoint.AnnotationsEntry - nil, // 93: felix.HostMetadataV4V6Update.LabelsEntry - nil, // 94: felix.ServiceAccountUpdate.LabelsEntry - nil, // 95: felix.NamespaceUpdate.LabelsEntry + (*QoSPolicy)(nil), // 38: felix.QoSPolicy + (*LocalBGPPeer)(nil), // 39: felix.LocalBGPPeer + (*WorkloadEndpointRemove)(nil), // 40: felix.WorkloadEndpointRemove + (*HostEndpointID)(nil), // 41: felix.HostEndpointID + (*HostEndpointUpdate)(nil), // 42: felix.HostEndpointUpdate + (*HostEndpoint)(nil), // 43: felix.HostEndpoint + (*HostEndpointRemove)(nil), // 44: felix.HostEndpointRemove + (*TierInfo)(nil), // 45: felix.TierInfo + (*NatInfo)(nil), // 46: felix.NatInfo + (*ProcessStatusUpdate)(nil), // 47: felix.ProcessStatusUpdate + (*HostEndpointStatusUpdate)(nil), // 48: felix.HostEndpointStatusUpdate + (*EndpointStatus)(nil), // 49: felix.EndpointStatus + (*HostEndpointStatusRemove)(nil), // 50: felix.HostEndpointStatusRemove + (*WorkloadEndpointStatusUpdate)(nil), // 51: felix.WorkloadEndpointStatusUpdate + (*WorkloadEndpointStatusRemove)(nil), // 52: felix.WorkloadEndpointStatusRemove + (*WireguardStatusUpdate)(nil), // 53: felix.WireguardStatusUpdate + (*DataplaneInSync)(nil), // 54: felix.DataplaneInSync + (*HostMetadataV4V6Update)(nil), // 55: felix.HostMetadataV4V6Update + (*HostMetadataV4V6Remove)(nil), // 56: felix.HostMetadataV4V6Remove + (*HostMetadataUpdate)(nil), // 57: felix.HostMetadataUpdate + (*HostMetadataRemove)(nil), // 58: felix.HostMetadataRemove + (*HostMetadataV6Update)(nil), // 59: felix.HostMetadataV6Update + (*HostMetadataV6Remove)(nil), // 60: felix.HostMetadataV6Remove + (*IPAMPoolUpdate)(nil), // 61: felix.IPAMPoolUpdate + (*IPAMPoolRemove)(nil), // 62: felix.IPAMPoolRemove + (*IPAMPool)(nil), // 63: felix.IPAMPool + (*Encapsulation)(nil), // 64: felix.Encapsulation + (*ServiceAccountUpdate)(nil), // 65: felix.ServiceAccountUpdate + (*ServiceAccountRemove)(nil), // 66: felix.ServiceAccountRemove + (*ServiceAccountID)(nil), // 67: felix.ServiceAccountID + (*NamespaceUpdate)(nil), // 68: felix.NamespaceUpdate + (*NamespaceRemove)(nil), // 69: felix.NamespaceRemove + (*NamespaceID)(nil), // 70: felix.NamespaceID + (*TunnelType)(nil), // 71: felix.TunnelType + (*RouteUpdate)(nil), // 72: felix.RouteUpdate + (*RouteRemove)(nil), // 73: felix.RouteRemove + (*VXLANTunnelEndpointUpdate)(nil), // 74: felix.VXLANTunnelEndpointUpdate + (*VXLANTunnelEndpointRemove)(nil), // 75: felix.VXLANTunnelEndpointRemove + (*ReportResult)(nil), // 76: felix.ReportResult + (*DataplaneStats)(nil), // 77: felix.DataplaneStats + (*Statistic)(nil), // 78: felix.Statistic + (*RuleTrace)(nil), // 79: felix.RuleTrace + (*WireguardEndpointUpdate)(nil), // 80: felix.WireguardEndpointUpdate + (*WireguardEndpointRemove)(nil), // 81: felix.WireguardEndpointRemove + (*WireguardEndpointV6Update)(nil), // 82: felix.WireguardEndpointV6Update + (*WireguardEndpointV6Remove)(nil), // 83: felix.WireguardEndpointV6Remove + (*GlobalBGPConfigUpdate)(nil), // 84: felix.GlobalBGPConfigUpdate + (*ServicePort)(nil), // 85: felix.ServicePort + (*ServiceUpdate)(nil), // 86: felix.ServiceUpdate + (*ServiceRemove)(nil), // 87: felix.ServiceRemove + nil, // 88: felix.ConfigUpdate.ConfigEntry + nil, // 89: felix.ConfigUpdate.SourceToRawConfigEntry + nil, // 90: felix.RawConfig.ConfigEntry + (*HTTPMatch_PathMatch)(nil), // 91: felix.HTTPMatch.PathMatch + nil, // 92: felix.RuleMetadata.AnnotationsEntry + nil, // 93: felix.WorkloadEndpoint.AnnotationsEntry + nil, // 94: felix.HostMetadataV4V6Update.LabelsEntry + nil, // 95: felix.ServiceAccountUpdate.LabelsEntry + nil, // 96: felix.NamespaceUpdate.LabelsEntry } var file_felixbackend_proto_depIdxs = []int32{ 14, // 0: felix.ToDataplane.in_sync:type_name -> felix.InSync @@ -6935,45 +7000,45 @@ var file_felixbackend_proto_depIdxs = []int32{ 19, // 5: felix.ToDataplane.active_profile_remove:type_name -> felix.ActiveProfileRemove 22, // 6: felix.ToDataplane.active_policy_update:type_name -> felix.ActivePolicyUpdate 23, // 7: felix.ToDataplane.active_policy_remove:type_name -> felix.ActivePolicyRemove - 41, // 8: felix.ToDataplane.host_endpoint_update:type_name -> felix.HostEndpointUpdate - 43, // 9: felix.ToDataplane.host_endpoint_remove:type_name -> felix.HostEndpointRemove + 42, // 8: felix.ToDataplane.host_endpoint_update:type_name -> felix.HostEndpointUpdate + 44, // 9: felix.ToDataplane.host_endpoint_remove:type_name -> felix.HostEndpointRemove 34, // 10: felix.ToDataplane.workload_endpoint_update:type_name -> felix.WorkloadEndpointUpdate - 39, // 11: felix.ToDataplane.workload_endpoint_remove:type_name -> felix.WorkloadEndpointRemove + 40, // 11: felix.ToDataplane.workload_endpoint_remove:type_name -> felix.WorkloadEndpointRemove 12, // 12: felix.ToDataplane.config_update:type_name -> felix.ConfigUpdate - 56, // 13: felix.ToDataplane.host_metadata_update:type_name -> felix.HostMetadataUpdate - 57, // 14: felix.ToDataplane.host_metadata_remove:type_name -> felix.HostMetadataRemove - 54, // 15: felix.ToDataplane.host_metadata_v4v6_update:type_name -> felix.HostMetadataV4V6Update - 55, // 16: felix.ToDataplane.host_metadata_v4v6_remove:type_name -> felix.HostMetadataV4V6Remove - 60, // 17: felix.ToDataplane.ipam_pool_update:type_name -> felix.IPAMPoolUpdate - 61, // 18: felix.ToDataplane.ipam_pool_remove:type_name -> felix.IPAMPoolRemove - 64, // 19: felix.ToDataplane.service_account_update:type_name -> felix.ServiceAccountUpdate - 65, // 20: felix.ToDataplane.service_account_remove:type_name -> felix.ServiceAccountRemove - 67, // 21: felix.ToDataplane.namespace_update:type_name -> felix.NamespaceUpdate - 68, // 22: felix.ToDataplane.namespace_remove:type_name -> felix.NamespaceRemove - 71, // 23: felix.ToDataplane.route_update:type_name -> felix.RouteUpdate - 72, // 24: felix.ToDataplane.route_remove:type_name -> felix.RouteRemove - 73, // 25: felix.ToDataplane.vtep_update:type_name -> felix.VXLANTunnelEndpointUpdate - 74, // 26: felix.ToDataplane.vtep_remove:type_name -> felix.VXLANTunnelEndpointRemove - 79, // 27: felix.ToDataplane.wireguard_endpoint_update:type_name -> felix.WireguardEndpointUpdate - 80, // 28: felix.ToDataplane.wireguard_endpoint_remove:type_name -> felix.WireguardEndpointRemove - 83, // 29: felix.ToDataplane.global_bgp_config_update:type_name -> felix.GlobalBGPConfigUpdate - 63, // 30: felix.ToDataplane.encapsulation:type_name -> felix.Encapsulation - 85, // 31: felix.ToDataplane.service_update:type_name -> felix.ServiceUpdate - 86, // 32: felix.ToDataplane.service_remove:type_name -> felix.ServiceRemove - 81, // 33: felix.ToDataplane.wireguard_endpoint_v6_update:type_name -> felix.WireguardEndpointV6Update - 82, // 34: felix.ToDataplane.wireguard_endpoint_v6_remove:type_name -> felix.WireguardEndpointV6Remove - 58, // 35: felix.ToDataplane.host_metadata_v6_update:type_name -> felix.HostMetadataV6Update - 59, // 36: felix.ToDataplane.host_metadata_v6_remove:type_name -> felix.HostMetadataV6Remove - 46, // 37: felix.FromDataplane.process_status_update:type_name -> felix.ProcessStatusUpdate - 47, // 38: felix.FromDataplane.host_endpoint_status_update:type_name -> felix.HostEndpointStatusUpdate - 49, // 39: felix.FromDataplane.host_endpoint_status_remove:type_name -> felix.HostEndpointStatusRemove - 50, // 40: felix.FromDataplane.workload_endpoint_status_update:type_name -> felix.WorkloadEndpointStatusUpdate - 51, // 41: felix.FromDataplane.workload_endpoint_status_remove:type_name -> felix.WorkloadEndpointStatusRemove - 52, // 42: felix.FromDataplane.wireguard_status_update:type_name -> felix.WireguardStatusUpdate - 53, // 43: felix.FromDataplane.dataplane_in_sync:type_name -> felix.DataplaneInSync - 87, // 44: felix.ConfigUpdate.config:type_name -> felix.ConfigUpdate.ConfigEntry - 88, // 45: felix.ConfigUpdate.source_to_raw_config:type_name -> felix.ConfigUpdate.SourceToRawConfigEntry - 89, // 46: felix.RawConfig.config:type_name -> felix.RawConfig.ConfigEntry + 57, // 13: felix.ToDataplane.host_metadata_update:type_name -> felix.HostMetadataUpdate + 58, // 14: felix.ToDataplane.host_metadata_remove:type_name -> felix.HostMetadataRemove + 55, // 15: felix.ToDataplane.host_metadata_v4v6_update:type_name -> felix.HostMetadataV4V6Update + 56, // 16: felix.ToDataplane.host_metadata_v4v6_remove:type_name -> felix.HostMetadataV4V6Remove + 61, // 17: felix.ToDataplane.ipam_pool_update:type_name -> felix.IPAMPoolUpdate + 62, // 18: felix.ToDataplane.ipam_pool_remove:type_name -> felix.IPAMPoolRemove + 65, // 19: felix.ToDataplane.service_account_update:type_name -> felix.ServiceAccountUpdate + 66, // 20: felix.ToDataplane.service_account_remove:type_name -> felix.ServiceAccountRemove + 68, // 21: felix.ToDataplane.namespace_update:type_name -> felix.NamespaceUpdate + 69, // 22: felix.ToDataplane.namespace_remove:type_name -> felix.NamespaceRemove + 72, // 23: felix.ToDataplane.route_update:type_name -> felix.RouteUpdate + 73, // 24: felix.ToDataplane.route_remove:type_name -> felix.RouteRemove + 74, // 25: felix.ToDataplane.vtep_update:type_name -> felix.VXLANTunnelEndpointUpdate + 75, // 26: felix.ToDataplane.vtep_remove:type_name -> felix.VXLANTunnelEndpointRemove + 80, // 27: felix.ToDataplane.wireguard_endpoint_update:type_name -> felix.WireguardEndpointUpdate + 81, // 28: felix.ToDataplane.wireguard_endpoint_remove:type_name -> felix.WireguardEndpointRemove + 84, // 29: felix.ToDataplane.global_bgp_config_update:type_name -> felix.GlobalBGPConfigUpdate + 64, // 30: felix.ToDataplane.encapsulation:type_name -> felix.Encapsulation + 86, // 31: felix.ToDataplane.service_update:type_name -> felix.ServiceUpdate + 87, // 32: felix.ToDataplane.service_remove:type_name -> felix.ServiceRemove + 82, // 33: felix.ToDataplane.wireguard_endpoint_v6_update:type_name -> felix.WireguardEndpointV6Update + 83, // 34: felix.ToDataplane.wireguard_endpoint_v6_remove:type_name -> felix.WireguardEndpointV6Remove + 59, // 35: felix.ToDataplane.host_metadata_v6_update:type_name -> felix.HostMetadataV6Update + 60, // 36: felix.ToDataplane.host_metadata_v6_remove:type_name -> felix.HostMetadataV6Remove + 47, // 37: felix.FromDataplane.process_status_update:type_name -> felix.ProcessStatusUpdate + 48, // 38: felix.FromDataplane.host_endpoint_status_update:type_name -> felix.HostEndpointStatusUpdate + 50, // 39: felix.FromDataplane.host_endpoint_status_remove:type_name -> felix.HostEndpointStatusRemove + 51, // 40: felix.FromDataplane.workload_endpoint_status_update:type_name -> felix.WorkloadEndpointStatusUpdate + 52, // 41: felix.FromDataplane.workload_endpoint_status_remove:type_name -> felix.WorkloadEndpointStatusRemove + 53, // 42: felix.FromDataplane.wireguard_status_update:type_name -> felix.WireguardStatusUpdate + 54, // 43: felix.FromDataplane.dataplane_in_sync:type_name -> felix.DataplaneInSync + 88, // 44: felix.ConfigUpdate.config:type_name -> felix.ConfigUpdate.ConfigEntry + 89, // 45: felix.ConfigUpdate.source_to_raw_config:type_name -> felix.ConfigUpdate.SourceToRawConfigEntry + 90, // 46: felix.RawConfig.config:type_name -> felix.RawConfig.ConfigEntry 4, // 47: felix.IPSetUpdate.type:type_name -> felix.IPSetUpdate.IPSetType 20, // 48: felix.ActiveProfileUpdate.id:type_name -> felix.ProfileID 21, // 49: felix.ActiveProfileUpdate.profile:type_name -> felix.Profile @@ -6998,66 +7063,67 @@ var file_felixbackend_proto_depIdxs = []int32{ 27, // 68: felix.Rule.dst_service_account_match:type_name -> felix.ServiceAccountMatch 28, // 69: felix.Rule.http_match:type_name -> felix.HTTPMatch 29, // 70: felix.Rule.metadata:type_name -> felix.RuleMetadata - 90, // 71: felix.HTTPMatch.paths:type_name -> felix.HTTPMatch.PathMatch - 91, // 72: felix.RuleMetadata.annotations:type_name -> felix.RuleMetadata.AnnotationsEntry + 91, // 71: felix.HTTPMatch.paths:type_name -> felix.HTTPMatch.PathMatch + 92, // 72: felix.RuleMetadata.annotations:type_name -> felix.RuleMetadata.AnnotationsEntry 33, // 73: felix.WorkloadEndpointUpdate.id:type_name -> felix.WorkloadEndpointID 36, // 74: felix.WorkloadEndpointUpdate.endpoint:type_name -> felix.WorkloadEndpoint - 44, // 75: felix.WorkloadEndpoint.tiers:type_name -> felix.TierInfo - 45, // 76: felix.WorkloadEndpoint.ipv4_nat:type_name -> felix.NatInfo - 45, // 77: felix.WorkloadEndpoint.ipv6_nat:type_name -> felix.NatInfo - 92, // 78: felix.WorkloadEndpoint.annotations:type_name -> felix.WorkloadEndpoint.AnnotationsEntry + 45, // 75: felix.WorkloadEndpoint.tiers:type_name -> felix.TierInfo + 46, // 76: felix.WorkloadEndpoint.ipv4_nat:type_name -> felix.NatInfo + 46, // 77: felix.WorkloadEndpoint.ipv6_nat:type_name -> felix.NatInfo + 93, // 78: felix.WorkloadEndpoint.annotations:type_name -> felix.WorkloadEndpoint.AnnotationsEntry 37, // 79: felix.WorkloadEndpoint.qos_controls:type_name -> felix.QoSControls - 38, // 80: felix.WorkloadEndpoint.local_bgp_peer:type_name -> felix.LocalBGPPeer + 39, // 80: felix.WorkloadEndpoint.local_bgp_peer:type_name -> felix.LocalBGPPeer 35, // 81: felix.WorkloadEndpoint.skip_redir:type_name -> felix.WorkloadBpfSkipRedir - 33, // 82: felix.WorkloadEndpointRemove.id:type_name -> felix.WorkloadEndpointID - 40, // 83: felix.HostEndpointUpdate.id:type_name -> felix.HostEndpointID - 42, // 84: felix.HostEndpointUpdate.endpoint:type_name -> felix.HostEndpoint - 44, // 85: felix.HostEndpoint.tiers:type_name -> felix.TierInfo - 44, // 86: felix.HostEndpoint.untracked_tiers:type_name -> felix.TierInfo - 44, // 87: felix.HostEndpoint.pre_dnat_tiers:type_name -> felix.TierInfo - 44, // 88: felix.HostEndpoint.forward_tiers:type_name -> felix.TierInfo - 40, // 89: felix.HostEndpointRemove.id:type_name -> felix.HostEndpointID - 40, // 90: felix.HostEndpointStatusUpdate.id:type_name -> felix.HostEndpointID - 48, // 91: felix.HostEndpointStatusUpdate.status:type_name -> felix.EndpointStatus - 40, // 92: felix.HostEndpointStatusRemove.id:type_name -> felix.HostEndpointID - 33, // 93: felix.WorkloadEndpointStatusUpdate.id:type_name -> felix.WorkloadEndpointID - 48, // 94: felix.WorkloadEndpointStatusUpdate.status:type_name -> felix.EndpointStatus - 36, // 95: felix.WorkloadEndpointStatusUpdate.endpoint:type_name -> felix.WorkloadEndpoint - 33, // 96: felix.WorkloadEndpointStatusRemove.id:type_name -> felix.WorkloadEndpointID - 0, // 97: felix.WireguardStatusUpdate.ip_version:type_name -> felix.IPVersion - 93, // 98: felix.HostMetadataV4V6Update.labels:type_name -> felix.HostMetadataV4V6Update.LabelsEntry - 62, // 99: felix.IPAMPoolUpdate.pool:type_name -> felix.IPAMPool - 66, // 100: felix.ServiceAccountUpdate.id:type_name -> felix.ServiceAccountID - 94, // 101: felix.ServiceAccountUpdate.labels:type_name -> felix.ServiceAccountUpdate.LabelsEntry - 66, // 102: felix.ServiceAccountRemove.id:type_name -> felix.ServiceAccountID - 69, // 103: felix.NamespaceUpdate.id:type_name -> felix.NamespaceID - 95, // 104: felix.NamespaceUpdate.labels:type_name -> felix.NamespaceUpdate.LabelsEntry - 69, // 105: felix.NamespaceRemove.id:type_name -> felix.NamespaceID - 1, // 106: felix.RouteUpdate.types:type_name -> felix.RouteType - 2, // 107: felix.RouteUpdate.ip_pool_type:type_name -> felix.IPPoolType - 70, // 108: felix.RouteUpdate.tunnel_type:type_name -> felix.TunnelType - 31, // 109: felix.DataplaneStats.protocol:type_name -> felix.Protocol - 77, // 110: felix.DataplaneStats.stats:type_name -> felix.Statistic - 78, // 111: felix.DataplaneStats.rules:type_name -> felix.RuleTrace - 3, // 112: felix.DataplaneStats.action:type_name -> felix.Action - 5, // 113: felix.Statistic.direction:type_name -> felix.Statistic.Direction - 6, // 114: felix.Statistic.relativity:type_name -> felix.Statistic.Relativity - 7, // 115: felix.Statistic.kind:type_name -> felix.Statistic.Kind - 3, // 116: felix.Statistic.action:type_name -> felix.Action - 24, // 117: felix.RuleTrace.policy:type_name -> felix.PolicyID - 20, // 118: felix.RuleTrace.profile:type_name -> felix.ProfileID - 8, // 119: felix.RuleTrace.direction:type_name -> felix.RuleTrace.Direction - 84, // 120: felix.ServiceUpdate.ports:type_name -> felix.ServicePort - 13, // 121: felix.ConfigUpdate.SourceToRawConfigEntry.value:type_name -> felix.RawConfig - 9, // 122: felix.PolicySync.Sync:input_type -> felix.SyncRequest - 76, // 123: felix.PolicySync.Report:input_type -> felix.DataplaneStats - 10, // 124: felix.PolicySync.Sync:output_type -> felix.ToDataplane - 75, // 125: felix.PolicySync.Report:output_type -> felix.ReportResult - 124, // [124:126] is the sub-list for method output_type - 122, // [122:124] is the sub-list for method input_type - 122, // [122:122] is the sub-list for extension type_name - 122, // [122:122] is the sub-list for extension extendee - 0, // [0:122] is the sub-list for field type_name + 38, // 82: felix.WorkloadEndpoint.qos_policies:type_name -> felix.QoSPolicy + 33, // 83: felix.WorkloadEndpointRemove.id:type_name -> felix.WorkloadEndpointID + 41, // 84: felix.HostEndpointUpdate.id:type_name -> felix.HostEndpointID + 43, // 85: felix.HostEndpointUpdate.endpoint:type_name -> felix.HostEndpoint + 45, // 86: felix.HostEndpoint.tiers:type_name -> felix.TierInfo + 45, // 87: felix.HostEndpoint.untracked_tiers:type_name -> felix.TierInfo + 45, // 88: felix.HostEndpoint.pre_dnat_tiers:type_name -> felix.TierInfo + 45, // 89: felix.HostEndpoint.forward_tiers:type_name -> felix.TierInfo + 41, // 90: felix.HostEndpointRemove.id:type_name -> felix.HostEndpointID + 41, // 91: felix.HostEndpointStatusUpdate.id:type_name -> felix.HostEndpointID + 49, // 92: felix.HostEndpointStatusUpdate.status:type_name -> felix.EndpointStatus + 41, // 93: felix.HostEndpointStatusRemove.id:type_name -> felix.HostEndpointID + 33, // 94: felix.WorkloadEndpointStatusUpdate.id:type_name -> felix.WorkloadEndpointID + 49, // 95: felix.WorkloadEndpointStatusUpdate.status:type_name -> felix.EndpointStatus + 36, // 96: felix.WorkloadEndpointStatusUpdate.endpoint:type_name -> felix.WorkloadEndpoint + 33, // 97: felix.WorkloadEndpointStatusRemove.id:type_name -> felix.WorkloadEndpointID + 0, // 98: felix.WireguardStatusUpdate.ip_version:type_name -> felix.IPVersion + 94, // 99: felix.HostMetadataV4V6Update.labels:type_name -> felix.HostMetadataV4V6Update.LabelsEntry + 63, // 100: felix.IPAMPoolUpdate.pool:type_name -> felix.IPAMPool + 67, // 101: felix.ServiceAccountUpdate.id:type_name -> felix.ServiceAccountID + 95, // 102: felix.ServiceAccountUpdate.labels:type_name -> felix.ServiceAccountUpdate.LabelsEntry + 67, // 103: felix.ServiceAccountRemove.id:type_name -> felix.ServiceAccountID + 70, // 104: felix.NamespaceUpdate.id:type_name -> felix.NamespaceID + 96, // 105: felix.NamespaceUpdate.labels:type_name -> felix.NamespaceUpdate.LabelsEntry + 70, // 106: felix.NamespaceRemove.id:type_name -> felix.NamespaceID + 1, // 107: felix.RouteUpdate.types:type_name -> felix.RouteType + 2, // 108: felix.RouteUpdate.ip_pool_type:type_name -> felix.IPPoolType + 71, // 109: felix.RouteUpdate.tunnel_type:type_name -> felix.TunnelType + 31, // 110: felix.DataplaneStats.protocol:type_name -> felix.Protocol + 78, // 111: felix.DataplaneStats.stats:type_name -> felix.Statistic + 79, // 112: felix.DataplaneStats.rules:type_name -> felix.RuleTrace + 3, // 113: felix.DataplaneStats.action:type_name -> felix.Action + 5, // 114: felix.Statistic.direction:type_name -> felix.Statistic.Direction + 6, // 115: felix.Statistic.relativity:type_name -> felix.Statistic.Relativity + 7, // 116: felix.Statistic.kind:type_name -> felix.Statistic.Kind + 3, // 117: felix.Statistic.action:type_name -> felix.Action + 24, // 118: felix.RuleTrace.policy:type_name -> felix.PolicyID + 20, // 119: felix.RuleTrace.profile:type_name -> felix.ProfileID + 8, // 120: felix.RuleTrace.direction:type_name -> felix.RuleTrace.Direction + 85, // 121: felix.ServiceUpdate.ports:type_name -> felix.ServicePort + 13, // 122: felix.ConfigUpdate.SourceToRawConfigEntry.value:type_name -> felix.RawConfig + 9, // 123: felix.PolicySync.Sync:input_type -> felix.SyncRequest + 77, // 124: felix.PolicySync.Report:input_type -> felix.DataplaneStats + 10, // 125: felix.PolicySync.Sync:output_type -> felix.ToDataplane + 76, // 126: felix.PolicySync.Report:output_type -> felix.ReportResult + 125, // [125:127] is the sub-list for method output_type + 123, // [123:125] is the sub-list for method input_type + 123, // [123:123] is the sub-list for extension type_name + 123, // [123:123] is the sub-list for extension extendee + 0, // [0:123] is the sub-list for field type_name } func init() { file_felixbackend_proto_init() } @@ -7123,12 +7189,12 @@ func file_felixbackend_proto_init() { (*Protocol_Number)(nil), (*Protocol_Name)(nil), } - file_felixbackend_proto_msgTypes[69].OneofWrappers = []any{ + file_felixbackend_proto_msgTypes[70].OneofWrappers = []any{ (*RuleTrace_Policy)(nil), (*RuleTrace_Profile)(nil), (*RuleTrace_None)(nil), } - file_felixbackend_proto_msgTypes[81].OneofWrappers = []any{ + file_felixbackend_proto_msgTypes[82].OneofWrappers = []any{ (*HTTPMatch_PathMatch_Exact)(nil), (*HTTPMatch_PathMatch_Prefix)(nil), } @@ -7138,7 +7204,7 @@ func file_felixbackend_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_felixbackend_proto_rawDesc), len(file_felixbackend_proto_rawDesc)), NumEnums: 9, - NumMessages: 87, + NumMessages: 88, NumExtensions: 0, NumServices: 1, }, diff --git a/felix/proto/felixbackend.proto b/felix/proto/felixbackend.proto index 1d516552ecd..453d6aea8ab 100644 --- a/felix/proto/felixbackend.proto +++ b/felix/proto/felixbackend.proto @@ -411,6 +411,7 @@ message WorkloadEndpoint { QoSControls qos_controls = 12; LocalBGPPeer local_bgp_peer = 13; WorkloadBpfSkipRedir skip_redir = 14; + repeated QoSPolicy qos_policies = 15; } message QoSControls { @@ -430,6 +431,11 @@ message QoSControls { int64 EgressPacketBurst = 14; } +message QoSPolicy { + string destination = 1; + int32 dscp = 2; +} + message LocalBGPPeer { string bgp_peer_name = 1; } diff --git a/felix/rules/nat.go b/felix/rules/nat.go index f5c22c9b4e7..096d55dd962 100644 --- a/felix/rules/nat.go +++ b/felix/rules/nat.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tigera, Inc. All rights reserved. +// Copyright (c) 2020-2025 Tigera, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ func (r *DefaultRuleRenderer) makeNATOutgoingRuleBPF(version uint8, protocol str func (r *DefaultRuleRenderer) makeNATOutgoingRuleIPTables(ipVersion uint8, protocol string, action Action) Rule { ipConf := r.ipSetConfig(ipVersion) - allIPsSetName := ipConf.NameForMainIPSet(IPSetIDNATOutgoingAllPools) + allIPsSetName := ipConf.NameForMainIPSet(IPSetIDAllPools) masqIPsSetName := ipConf.NameForMainIPSet(IPSetIDNATOutgoingMasqPools) match := r.NewMatch(). diff --git a/felix/rules/qos.go b/felix/rules/qos.go new file mode 100644 index 00000000000..fa5d2dbe11a --- /dev/null +++ b/felix/rules/qos.go @@ -0,0 +1,36 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "github.com/projectcalico/calico/felix/dataplane/linux/qos" + "github.com/projectcalico/calico/felix/generictables" +) + +func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []qos.Policy, ipVersion uint8) *generictables.Chain { + var rules []generictables.Rule + // Policies is sorted and validated by QoS policy manager. + for _, p := range policies { + rules = append(rules, generictables.Rule{ + Match: r.NewMatch().SourceNet(p.SrcAddrs), + Action: r.DSCP(p.DSCP, ipVersion), + }) + } + + return &generictables.Chain{ + Name: ChainQoSPolicy, + Rules: rules, + } +} diff --git a/felix/rules/qos_test.go b/felix/rules/qos_test.go new file mode 100644 index 00000000000..f7b346065df --- /dev/null +++ b/felix/rules/qos_test.go @@ -0,0 +1,106 @@ +// Copyright (c) 2025 Tigera, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/projectcalico/calico/felix/dataplane/linux/qos" + "github.com/projectcalico/calico/felix/generictables" + . "github.com/projectcalico/calico/felix/iptables" + . "github.com/projectcalico/calico/felix/rules" +) + +var _ = Describe("QoS", func() { + rrConfigNormal := Config{ + IPIPEnabled: true, + MarkAccept: 0x8, + MarkPass: 0x10, + MarkScratch0: 0x20, + MarkScratch1: 0x40, + MarkDrop: 0x80, + MarkEndpoint: 0xff00, + } + + var renderer RuleRenderer + BeforeEach(func() { + renderer = NewRenderer(rrConfigNormal) + }) + + It("should render empty chain for no policies", func() { + Expect(renderer.EgressQoSPolicyChain([]qos.Policy{}, 4)).To(Equal(&generictables.Chain{ + Name: "cali-qos-policy", + Rules: nil, + })) + }) + + It("should render empty IPv6 chain for no policies", func() { + Expect(renderer.EgressQoSPolicyChain(nil, 6)).To(Equal(&generictables.Chain{ + Name: "cali-qos-policy", + Rules: nil, + })) + }) + + It("should render correct chain for policies", func() { + policies := []qos.Policy{ + {SrcAddrs: "192.168.10.20", DSCP: 10}, + {SrcAddrs: "192.168.10.100,172.17.1.100", DSCP: 40}, + {SrcAddrs: "192.168.20.1", DSCP: 0}, + } + Expect(renderer.EgressQoSPolicyChain(policies, 4)).To(Equal(&generictables.Chain{ + Name: "cali-qos-policy", + Rules: []generictables.Rule{ + { + Match: Match().SourceNet("192.168.10.20"), + Action: DSCPAction{Value: 10}, + }, + { + Match: Match().SourceNet("192.168.10.100,172.17.1.100"), + Action: DSCPAction{Value: 40}, + }, + { + Match: Match().SourceNet("192.168.20.1"), + Action: DSCPAction{Value: 0}, + }, + }, + })) + }) + + It("should render correct IPv6 chain for policies", func() { + policies := []qos.Policy{ + {SrcAddrs: "dead:beef::1:20", DSCP: 10}, + {SrcAddrs: "dead:beef::1:100,dead:beef::10:1", DSCP: 40}, + {SrcAddrs: "dead:beef::2:2", DSCP: 22}, + } + Expect(renderer.EgressQoSPolicyChain(policies, 6)).To(Equal(&generictables.Chain{ + Name: "cali-qos-policy", + Rules: []generictables.Rule{ + { + Match: Match().SourceNet("dead:beef::1:20"), + Action: DSCPAction{Value: 10}, + }, + { + Match: Match().SourceNet("dead:beef::1:100,dead:beef::10:1"), + Action: DSCPAction{Value: 40}, + }, + { + Match: Match().SourceNet("dead:beef::2:2"), + Action: DSCPAction{Value: 22}, + }, + }, + })) + }) +}) diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index ed8616edae2..3ab05ed9e45 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -23,6 +23,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/projectcalico/calico/felix/config" + "github.com/projectcalico/calico/felix/dataplane/linux/qos" "github.com/projectcalico/calico/felix/generictables" "github.com/projectcalico/calico/felix/ipsets" "github.com/projectcalico/calico/felix/iptables" @@ -61,7 +62,9 @@ const ( ChainManglePrerouting = ChainNamePrefix + "PREROUTING" ChainManglePostrouting = ChainNamePrefix + "POSTROUTING" - IPSetIDNATOutgoingAllPools = "all-ipam-pools" + ChainQoSPolicy = ChainNamePrefix + "qos-policy" + + IPSetIDAllPools = "all-ipam-pools" IPSetIDNATOutgoingMasqPools = "masq-ipam-pools" IPSetIDAllHostNets = "all-hosts-net" @@ -320,6 +323,8 @@ type RuleRenderer interface { NATOutgoingChain(active bool, ipVersion uint8) *generictables.Chain + EgressQoSPolicyChain(policies []qos.Policy, ipVersion uint8) *generictables.Chain + DNATsToIptablesChains(dnats map[string]string) []*generictables.Chain SNATsToIptablesChains(snats map[string]string) []*generictables.Chain BlockedCIDRsToIptablesChains(cidrs []string, ipVersion uint8) []*generictables.Chain diff --git a/felix/rules/static.go b/felix/rules/static.go index 59d51d0b555..6d33dbc6db0 100644 --- a/felix/rules/static.go +++ b/felix/rules/static.go @@ -1065,6 +1065,16 @@ func (r *DefaultRuleRenderer) StaticManglePostroutingChain(ipVersion uint8) *gen // mangle table is typically used, if at all, for packet manipulations that might need to // apply to our allowed traffic. + ipConf := r.ipSetConfig(ipVersion) + allIPsSetName := ipConf.NameForMainIPSet(IPSetIDAllPools) + rules = append(rules, generictables.Rule{ + Match: r.NewMatch(). + SourceIPSet(allIPsSetName). + NotDestIPSet(allIPsSetName), + Action: r.Jump(ChainQoSPolicy), + Comment: []string{"QoS policy for traffic leaving cluster"}, + }) + // Allow immediately if IptablesMarkAccept is set. Our filter-FORWARD chain sets this for // any packets that reach the end of that chain. The principle is that we don't want to // apply normal host endpoint policy to forwarded traffic. diff --git a/felix/rules/static_test.go b/felix/rules/static_test.go index 39e36e2c249..1b118ee3abd 100644 --- a/felix/rules/static_test.go +++ b/felix/rules/static_test.go @@ -41,8 +41,15 @@ var _ = Describe("Static", func() { }) checkManglePostrouting := func(ipVersion uint8, ipvs bool) { + allIPSetName := fmt.Sprintf("cali%v0all-ipam-pools", ipVersion) It("should generate expected cali-POSTROUTING chain in the mangle table", func() { expRules := []generictables.Rule{ + // Evaluate QoS policies. + { + Match: Match().SourceIPSet(allIPSetName).NotDestIPSet(allIPSetName), + Action: JumpAction{Target: ChainQoSPolicy}, + Comment: []string{"QoS policy for traffic leaving cluster"}, + }, // Accept already accepted. { Match: Match().MarkSingleBitSet(0x10), diff --git a/libcalico-go/lib/apis/v3/generated.openapi.go b/libcalico-go/lib/apis/v3/generated.openapi.go index 98899ba8d8a..46ba1684816 100644 --- a/libcalico-go/lib/apis/v3/generated.openapi.go +++ b/libcalico-go/lib/apis/v3/generated.openapi.go @@ -3253,9 +3253,16 @@ func schema_libcalico_go_lib_apis_v3_QoSControls(ref common.ReferenceCallback) c Format: "int64", }, }, + "dscp": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/projectcalico/api/pkg/lib/numorstring.DSCP"), + }, + }, }, }, }, + Dependencies: []string{ + "github.com/projectcalico/api/pkg/lib/numorstring.DSCP"}, } } diff --git a/libcalico-go/lib/apis/v3/workloadendpoint.go b/libcalico-go/lib/apis/v3/workloadendpoint.go index fdde197fbb6..5608d7440b2 100644 --- a/libcalico-go/lib/apis/v3/workloadendpoint.go +++ b/libcalico-go/lib/apis/v3/workloadendpoint.go @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Tigera, Inc. All rights reserved. +// Copyright (c) 2017-2025 Tigera, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -178,6 +178,8 @@ type QoSControls struct { // Egress maximum number of connections (absolute number of connections, no unit). Only // applied if non-zero. When non-zero, must be between 1 and 4294967295. EgressMaxConnections int64 `json:"egressMaxConnections,omitempty"` + + DSCP *numorstring.DSCP `json:"dscp,omitempty"` } // NewWorkloadEndpoint creates a new (zeroed) WorkloadEndpoint struct with the TypeMetadata initialised to the current diff --git a/libcalico-go/lib/apis/v3/zz_generated.deepcopy.go b/libcalico-go/lib/apis/v3/zz_generated.deepcopy.go index 7763e41e5b5..7e2257ccf5a 100644 --- a/libcalico-go/lib/apis/v3/zz_generated.deepcopy.go +++ b/libcalico-go/lib/apis/v3/zz_generated.deepcopy.go @@ -632,6 +632,11 @@ func (in *OrchRef) DeepCopy() *OrchRef { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *QoSControls) DeepCopyInto(out *QoSControls) { *out = *in + if in.DSCP != nil { + in, out := &in.DSCP, &out.DSCP + *out = new(numorstring.DSCP) + **out = **in + } return } @@ -753,7 +758,7 @@ func (in *WorkloadEndpointSpec) DeepCopyInto(out *WorkloadEndpointSpec) { if in.QoSControls != nil { in, out := &in.QoSControls, &out.QoSControls *out = new(QoSControls) - **out = **in + (*in).DeepCopyInto(*out) } return } diff --git a/libcalico-go/lib/backend/k8s/conversion/constants.go b/libcalico-go/lib/backend/k8s/conversion/constants.go index f5c82ba5dae..f85032c52ac 100644 --- a/libcalico-go/lib/backend/k8s/conversion/constants.go +++ b/libcalico-go/lib/backend/k8s/conversion/constants.go @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2024 Tigera, Inc. All rights reserved. +// Copyright (c) 2017-2025 Tigera, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -65,4 +65,5 @@ const ( AnnotationQoSEgressPacketBurst = "qos.projectcalico.org/egressPacketBurst" AnnotationQoSIngressMaxConnections = "qos.projectcalico.org/ingressMaxConnections" AnnotationQoSEgressMaxConnections = "qos.projectcalico.org/egressMaxConnections" + AnnotationQoSEgressDSCP = "qos.projectcalico.org/egressDSCP" ) diff --git a/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go b/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go index 79d39bb1517..0a66cf56cc6 100644 --- a/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go +++ b/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 Tigera, Inc. All rights reserved. +// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -529,6 +529,12 @@ func handleQoSControlsAnnotations(annotations map[string]string) (*libapiv3.QoSC qosControls.EgressPacketBurst = defaultPacketBurst.Value() } + // Calico DSCP value for egress traffic annotation. + if str, found := annotations[AnnotationQoSEgressDSCP]; found { + value := numorstring.DSCPFromString(str) + qosControls.DSCP = &value + } + // return nil if no control is configured if (*qosControls == libapiv3.QoSControls{}) { qosControls = nil From 39f72586573ece2fd17b65041a48b71982b37a37 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Wed, 6 Aug 2025 12:41:06 -0700 Subject: [PATCH 02/15] fix --- felix/dataplane/linux/qos/qos.go | 5 ----- felix/dataplane/linux/qos_policy_mgr.go | 15 +++++++-------- felix/rules/qos.go | 8 ++++++-- felix/rules/qos_test.go | 7 +++---- felix/rules/rule_defs.go | 3 +-- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/felix/dataplane/linux/qos/qos.go b/felix/dataplane/linux/qos/qos.go index 441f9dd3754..423edef68a3 100644 --- a/felix/dataplane/linux/qos/qos.go +++ b/felix/dataplane/linux/qos/qos.go @@ -485,8 +485,3 @@ func updateTBF(tbs *TokenBucketState, workloadDevice netlink.Link) error { } return nil } - -type Policy struct { - SrcAddrs string - DSCP uint8 -} diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go index e107255f3ba..1446517e435 100644 --- a/felix/dataplane/linux/qos_policy_mgr.go +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -20,7 +20,6 @@ import ( "github.com/sirupsen/logrus" - "github.com/projectcalico/calico/felix/dataplane/linux/qos" "github.com/projectcalico/calico/felix/proto" "github.com/projectcalico/calico/felix/rules" "github.com/projectcalico/calico/felix/types" @@ -33,7 +32,7 @@ type qosPolicyManager struct { // QoS policy mangleTable Table dirty bool - qosPolicies map[types.WorkloadEndpointID]qos.Policy + policies map[types.WorkloadEndpointID]rules.QoSPolicy logCxt *logrus.Entry } @@ -45,7 +44,7 @@ func newQoSPolicyManager( ) *qosPolicyManager { return &qosPolicyManager{ ipVersion: ipVersion, - qosPolicies: map[types.WorkloadEndpointID]qos.Policy{}, + policies: map[types.WorkloadEndpointID]rules.QoSPolicy{}, dirty: true, mangleTable: mangleTable, ruleRenderer: ruleRenderer, @@ -65,9 +64,9 @@ func (m *qosPolicyManager) OnUpdate(msg interface{}) { func (m *qosPolicyManager) handleWlEndpointUpdates(wlID *proto.WorkloadEndpointID, msg *proto.WorkloadEndpointUpdate) { id := types.ProtoToWorkloadEndpointID(wlID) if msg == nil || len(msg.Endpoint.QosPolicies) == 0 { - _, exists := m.qosPolicies[id] + _, exists := m.policies[id] if exists { - delete(m.qosPolicies, id) + delete(m.policies, id) m.dirty = true } return @@ -85,7 +84,7 @@ func (m *qosPolicyManager) handleWlEndpointUpdates(wlID *proto.WorkloadEndpointI ips = msg.Endpoint.Ipv6Nets } if len(ips) != 0 { - m.qosPolicies[id] = qos.Policy{ + m.policies[id] = rules.QoSPolicy{ SrcAddrs: normaliseSourceAddr(ips), DSCP: uint8(dscp), } @@ -104,8 +103,8 @@ func normaliseSourceAddr(addrs []string) string { func (m *qosPolicyManager) CompleteDeferredWork() error { if m.dirty { - var policies []qos.Policy - for _, p := range m.qosPolicies { + var policies []rules.QoSPolicy + for _, p := range m.policies { policies = append(policies, p) } sort.Slice(policies, func(i, j int) bool { diff --git a/felix/rules/qos.go b/felix/rules/qos.go index fa5d2dbe11a..833bf35228a 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -15,11 +15,15 @@ package rules import ( - "github.com/projectcalico/calico/felix/dataplane/linux/qos" "github.com/projectcalico/calico/felix/generictables" ) -func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []qos.Policy, ipVersion uint8) *generictables.Chain { +type QoSPolicy struct { + SrcAddrs string + DSCP uint8 +} + +func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []QoSPolicy, ipVersion uint8) *generictables.Chain { var rules []generictables.Rule // Policies is sorted and validated by QoS policy manager. for _, p := range policies { diff --git a/felix/rules/qos_test.go b/felix/rules/qos_test.go index f7b346065df..ee6ff3ccc08 100644 --- a/felix/rules/qos_test.go +++ b/felix/rules/qos_test.go @@ -18,7 +18,6 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/projectcalico/calico/felix/dataplane/linux/qos" "github.com/projectcalico/calico/felix/generictables" . "github.com/projectcalico/calico/felix/iptables" . "github.com/projectcalico/calico/felix/rules" @@ -41,7 +40,7 @@ var _ = Describe("QoS", func() { }) It("should render empty chain for no policies", func() { - Expect(renderer.EgressQoSPolicyChain([]qos.Policy{}, 4)).To(Equal(&generictables.Chain{ + Expect(renderer.EgressQoSPolicyChain([]QoSPolicy{}, 4)).To(Equal(&generictables.Chain{ Name: "cali-qos-policy", Rules: nil, })) @@ -55,7 +54,7 @@ var _ = Describe("QoS", func() { }) It("should render correct chain for policies", func() { - policies := []qos.Policy{ + policies := []QoSPolicy{ {SrcAddrs: "192.168.10.20", DSCP: 10}, {SrcAddrs: "192.168.10.100,172.17.1.100", DSCP: 40}, {SrcAddrs: "192.168.20.1", DSCP: 0}, @@ -80,7 +79,7 @@ var _ = Describe("QoS", func() { }) It("should render correct IPv6 chain for policies", func() { - policies := []qos.Policy{ + policies := []QoSPolicy{ {SrcAddrs: "dead:beef::1:20", DSCP: 10}, {SrcAddrs: "dead:beef::1:100,dead:beef::10:1", DSCP: 40}, {SrcAddrs: "dead:beef::2:2", DSCP: 22}, diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index 3ab05ed9e45..7a2b19479d9 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -23,7 +23,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/projectcalico/calico/felix/config" - "github.com/projectcalico/calico/felix/dataplane/linux/qos" "github.com/projectcalico/calico/felix/generictables" "github.com/projectcalico/calico/felix/ipsets" "github.com/projectcalico/calico/felix/iptables" @@ -323,7 +322,7 @@ type RuleRenderer interface { NATOutgoingChain(active bool, ipVersion uint8) *generictables.Chain - EgressQoSPolicyChain(policies []qos.Policy, ipVersion uint8) *generictables.Chain + EgressQoSPolicyChain(policies []QoSPolicy, ipVersion uint8) *generictables.Chain DNATsToIptablesChains(dnats map[string]string) []*generictables.Chain SNATsToIptablesChains(snats map[string]string) []*generictables.Chain From d70aa1296d9e1546aeba809733ecb27360421e2d Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Wed, 6 Aug 2025 15:25:18 -0700 Subject: [PATCH 03/15] update tests --- api/pkg/lib/numorstring/dscp.go | 2 +- felix/dataplane/linux/qos_policy_mgr_test.go | 150 +++++++++---------- 2 files changed, 68 insertions(+), 84 deletions(-) diff --git a/api/pkg/lib/numorstring/dscp.go b/api/pkg/lib/numorstring/dscp.go index cc3755f9d0c..663f05bac74 100644 --- a/api/pkg/lib/numorstring/dscp.go +++ b/api/pkg/lib/numorstring/dscp.go @@ -77,7 +77,7 @@ func DSCPFromInt(v uint8) DSCP { // DSCPFromString creates a DSCP struct from a string value. func DSCPFromString(s string) DSCP { - for k, _ := range AllDSCPValues { + for k := range AllDSCPValues { if strings.EqualFold(k, s) { return DSCP( Uint8OrString{Type: NumOrStringString, StrVal: s}, diff --git a/felix/dataplane/linux/qos_policy_mgr_test.go b/felix/dataplane/linux/qos_policy_mgr_test.go index 964ebfa7ce1..faed4e7b10d 100644 --- a/felix/dataplane/linux/qos_policy_mgr_test.go +++ b/felix/dataplane/linux/qos_policy_mgr_test.go @@ -19,51 +19,38 @@ import ( . "github.com/onsi/gomega" "github.com/projectcalico/calico/felix/generictables" - "github.com/projectcalico/calico/felix/ipsets" "github.com/projectcalico/calico/felix/iptables" "github.com/projectcalico/calico/felix/proto" "github.com/projectcalico/calico/felix/rules" ) -var _ = Describe("QoS policy manager", func() { - var ( - manager *qosPolicyManager - mangleTable *mockTable - ruleRenderer rules.RuleRenderer - ) - - BeforeEach(func() { - mangleTable = newMockTable("mangle") - ruleRenderer = rules.NewRenderer(rules.Config{ - IPSetConfigV4: ipsets.NewIPVersionConfig( - ipsets.IPFamilyV4, - "cali", - nil, - nil, - ), - MarkPass: 0x1, - MarkAccept: 0x2, - MarkScratch0: 0x4, - MarkScratch1: 0x8, - MarkDrop: 0x10, - MarkEndpoint: 0x11110000, - }) - manager = newQoSPolicyManager(mangleTable, ruleRenderer, 4) - }) +var _ = Describe("QoS policy manager IPv4", qosPolicyManagerTests(4)) +var _ = Describe("QoS policy manager IPv6", qosPolicyManagerTests(6)) + +func qosPolicyManagerTests(ipVersion uint8) func() { + return func() { + var ( + manager *qosPolicyManager + mangleTable *mockTable + ruleRenderer rules.RuleRenderer + ) - Describe("QoS policy: after adding a workload with DSCP annotation", func() { BeforeEach(func() { - manager.OnUpdate(&proto.IPAMPoolUpdate{ - Id: "pool-1", - Pool: &proto.IPAMPool{ - Cidr: "10.0.0.0/16", - }, + mangleTable = newMockTable("mangle") + ruleRenderer = rules.NewRenderer(rules.Config{ + MarkPass: 0x1, + MarkAccept: 0x2, + MarkScratch0: 0x4, + MarkScratch1: 0x8, + MarkDrop: 0x10, + MarkEndpoint: 0x11110000, }) - err := manager.CompleteDeferredWork() - Expect(err).ToNot(HaveOccurred()) + manager = newQoSPolicyManager(mangleTable, ruleRenderer, ipVersion) }) It("should program QoS policy chain with no rule", func() { + err := manager.CompleteDeferredWork() + Expect(err).ToNot(HaveOccurred()) mangleTable.checkChains([][]*generictables.Chain{{{ Name: rules.ChainQoSPolicy, Rules: nil, @@ -72,15 +59,16 @@ var _ = Describe("QoS policy manager", func() { It("should handle workload updates correctly", func() { By("sending workload endpoint updates with DSCP annotion") + endpoint1 := &proto.WorkloadEndpoint{ + State: "active", + Name: "cali12345-ab", + Ipv4Nets: []string{"10.0.240.2/24", "20.0.240.2/24"}, + Ipv6Nets: []string{"2001:db8:2::2/112", "dead:beef::2/112"}, + QosPolicies: []*proto.QoSPolicy{{Dscp: 44}}, + } manager.OnUpdate(&proto.WorkloadEndpointUpdate{ - Id: &wlEPID1, - Endpoint: &proto.WorkloadEndpoint{ - State: "active", - Name: "cali12345-ab", - Ipv4Nets: []string{"10.0.240.2/24"}, - Ipv6Nets: []string{"2001:db8:2::2/128"}, - QosPolicies: []*proto.QoSPolicy{{Dscp: 44}}, - }, + Id: &wlEPID1, + Endpoint: endpoint1, }) err := manager.CompleteDeferredWork() @@ -91,22 +79,22 @@ var _ = Describe("QoS policy manager", func() { Rules: []generictables.Rule{ { Action: iptables.DSCPAction{Value: 44}, - Match: iptables.Match(). - SourceNet("10.0.240.2"), + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint1, ipVersion)), }, }, }}}) By("sending another workload endpoint updates with DSCP annotion") + endpoint2 := &proto.WorkloadEndpoint{ + State: "active", + Name: "cali2", + Ipv4Nets: []string{"10.0.240.1/24"}, + Ipv6Nets: []string{"2001:db8:2::1/112"}, + QosPolicies: []*proto.QoSPolicy{{Dscp: 20}}, + } manager.OnUpdate(&proto.WorkloadEndpointUpdate{ - Id: &wlEPID2, - Endpoint: &proto.WorkloadEndpoint{ - State: "active", - Name: "cali2", - Ipv4Nets: []string{"10.0.240.3/24"}, - Ipv6Nets: []string{"2001:db8:2::3/128"}, - QosPolicies: []*proto.QoSPolicy{{Dscp: 20}}, - }, + Id: &wlEPID2, + Endpoint: endpoint2, }) err = manager.CompleteDeferredWork() @@ -115,29 +103,23 @@ var _ = Describe("QoS policy manager", func() { mangleTable.checkChains([][]*generictables.Chain{{{ Name: rules.ChainQoSPolicy, Rules: []generictables.Rule{ + // Rendered policies are sorted. { - Action: iptables.DSCPAction{Value: 44}, - Match: iptables.Match(). - SourceNet("10.0.240.2"), + Action: iptables.DSCPAction{Value: 20}, + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint2, ipVersion)), }, { - Action: iptables.DSCPAction{Value: 20}, - Match: iptables.Match(). - SourceNet("10.0.240.3"), + Action: iptables.DSCPAction{Value: 44}, + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint1, ipVersion)), }, }, }}}) By("verifying update to DSCP value takes effect") + endpoint1.QosPolicies = []*proto.QoSPolicy{{Dscp: 13}} manager.OnUpdate(&proto.WorkloadEndpointUpdate{ - Id: &wlEPID1, - Endpoint: &proto.WorkloadEndpoint{ - State: "active", - Name: "cali12345-ab", - Ipv4Nets: []string{"10.0.240.2/24"}, - Ipv6Nets: []string{"2001:db8:2::2/128"}, - QosPolicies: []*proto.QoSPolicy{{Dscp: 13}}, - }, + Id: &wlEPID1, + Endpoint: endpoint1, }) err = manager.CompleteDeferredWork() @@ -146,28 +128,23 @@ var _ = Describe("QoS policy manager", func() { mangleTable.checkChains([][]*generictables.Chain{{{ Name: rules.ChainQoSPolicy, Rules: []generictables.Rule{ + // Rendered policies are sorted. { - Action: iptables.DSCPAction{Value: 13}, - Match: iptables.Match(). - SourceNet("10.0.240.2"), + Action: iptables.DSCPAction{Value: 20}, + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint2, ipVersion)), }, { - Action: iptables.DSCPAction{Value: 20}, - Match: iptables.Match(). - SourceNet("10.0.240.3"), + Action: iptables.DSCPAction{Value: 13}, + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint1, ipVersion)), }, }, }}}) By("verifying QoS policy rules removed when annotation is removed") + endpoint1.QosPolicies = nil manager.OnUpdate(&proto.WorkloadEndpointUpdate{ - Id: &wlEPID1, - Endpoint: &proto.WorkloadEndpoint{ - State: "active", - Name: "cali12345-ab", - Ipv4Nets: []string{"10.0.240.2/24"}, - Ipv6Nets: []string{"2001:db8:2::2/128"}, - }, + Id: &wlEPID1, + Endpoint: endpoint1, }) err = manager.CompleteDeferredWork() @@ -178,8 +155,7 @@ var _ = Describe("QoS policy manager", func() { Rules: []generictables.Rule{ { Action: iptables.DSCPAction{Value: 20}, - Match: iptables.Match(). - SourceNet("10.0.240.3"), + Match: iptables.Match().SourceNet(addrFromWlUpdate(endpoint2, ipVersion)), }, }, }}}) @@ -197,5 +173,13 @@ var _ = Describe("QoS policy manager", func() { Rules: nil, }}}) }) - }) -}) + } +} + +func addrFromWlUpdate(endpoint *proto.WorkloadEndpoint, ipVersion uint8) string { + addr := endpoint.Ipv4Nets + if ipVersion == 6 { + addr = endpoint.Ipv6Nets + } + return normaliseSourceAddr(addr) +} From 4f5b44c5e8ba81610434830bba8665f4cae9d8cc Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Wed, 6 Aug 2025 16:09:10 -0700 Subject: [PATCH 04/15] add more UTs --- api/pkg/lib/numorstring/numorstring_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/api/pkg/lib/numorstring/numorstring_test.go b/api/pkg/lib/numorstring/numorstring_test.go index e1c0472afda..1b589ea211c 100644 --- a/api/pkg/lib/numorstring/numorstring_test.go +++ b/api/pkg/lib/numorstring/numorstring_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017 Tigera, Inc. All rights reserved. +// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,9 +25,9 @@ import ( ) func init() { - asNumberType := reflect.TypeOf(numorstring.ASNumber(0)) protocolType := reflect.TypeOf(numorstring.Protocol{}) + dscpType := reflect.TypeOf(numorstring.DSCP{}) portType := reflect.TypeOf(numorstring.Port{}) // Perform tests of JSON unmarshaling of the various field types. @@ -90,6 +90,11 @@ func init() { Entry("should accept 0 protocol as string", "\"255\"", protocolType, numorstring.ProtocolFromInt(255)), Entry("should accept 256 protocol as string", "\"256\"", protocolType, numorstring.ProtocolFromString("256")), Entry("should reject bad protocol string", "\"25", protocolType, nil), + + // DSCP tests. + Entry("should accept 0 DSCP as int", "0", dscpType, numorstring.DSCPFromInt(0)), + Entry("should accept 63 DSCP as int", "63", dscpType, numorstring.DSCPFromInt(63)), + Entry("should accept DF DSCP as string", "\"DF\"", dscpType, numorstring.DSCPFromString(numorstring.DF)), ) // Perform tests of JSON marshaling of the various field types. From 43c866dcdfcb958f944c75e44fcc9aa91fe32070 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Mon, 11 Aug 2025 16:32:22 -0700 Subject: [PATCH 05/15] more tests --- api/pkg/lib/numorstring/dscp.go | 22 +++++++++++++++++-- felix/calc/event_sequencer_test.go | 13 ++++++++++- .../lib/backend/k8s/conversion/constants.go | 2 +- .../conversion/workload_endpoint_default.go | 9 ++++++-- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/api/pkg/lib/numorstring/dscp.go b/api/pkg/lib/numorstring/dscp.go index 663f05bac74..c56add15ac0 100644 --- a/api/pkg/lib/numorstring/dscp.go +++ b/api/pkg/lib/numorstring/dscp.go @@ -14,7 +14,10 @@ package numorstring -import "strings" +import ( + "fmt" + "strings" +) const ( // Default forwarding, i.e. best effort. @@ -97,13 +100,28 @@ func (d *DSCP) ToUint8() uint8 { return val } - val, valid := AllDSCPValues[d.StrVal] + val, valid := AllDSCPValues[strings.ToUpper(strings.TrimSpace(d.StrVal))] if !valid { return 0 } return val } +func (d *DSCP) Validate() error { + // If a number, it must be between 0 and 63. + val, err := (*Uint8OrString)(d).NumValue() + if err == nil && val > 63 { + return fmt.Errorf("DSCP must be between 0 and 63") + } + + // Otherwise, it must be one of the known constant. + _, valid := AllDSCPValues[strings.ToUpper(strings.TrimSpace(d.StrVal))] + if !valid { + return fmt.Errorf("%s is not a valid DSCP value", d.StrVal) + } + return nil +} + // UnmarshalJSON implements the json.Unmarshaller interface. func (d *DSCP) UnmarshalJSON(b []byte) error { return (*Uint8OrString)(d).UnmarshalJSON(b) diff --git a/felix/calc/event_sequencer_test.go b/felix/calc/event_sequencer_test.go index c4a6ddd7ff9..ba1832f3bbb 100644 --- a/felix/calc/event_sequencer_test.go +++ b/felix/calc/event_sequencer_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2024 Tigera, Inc. All rights reserved. +// Copyright (c) 2017-2025 Tigera, Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import ( . "github.com/onsi/gomega" googleproto "google.golang.org/protobuf/proto" + "github.com/projectcalico/api/pkg/lib/numorstring" "github.com/projectcalico/calico/felix/calc" "github.com/projectcalico/calico/felix/config" "github.com/projectcalico/calico/felix/proto" @@ -29,6 +30,10 @@ import ( "github.com/projectcalico/calico/libcalico-go/lib/net" ) +var ( + dscp numorstring.DSCP = numorstring.DSCPFromString("AF43") +) + var _ = DescribeTable("ModelWorkloadEndpointToProto", func(in model.WorkloadEndpoint, expected *proto.WorkloadEndpoint) { out := calc.ModelWorkloadEndpointToProto(&in, nil, []*proto.TierInfo{}) @@ -110,6 +115,7 @@ var _ = DescribeTable("ModelWorkloadEndpointToProto", EgressPacketBurst: 12000000, IngressMaxConnections: 13000000, EgressMaxConnections: 14000000, + DSCP: &dscp, }, }, &proto.WorkloadEndpoint{ State: "up", @@ -143,6 +149,11 @@ var _ = DescribeTable("ModelWorkloadEndpointToProto", IngressMaxConnections: 13000000, EgressMaxConnections: 14000000, }, + QosPolicies: []*proto.QoSPolicy{ + &proto.QoSPolicy{ + Dscp: 38, + }, + }, SkipRedir: &proto.WorkloadBpfSkipRedir{Ingress: true, Egress: true}, }), ) diff --git a/libcalico-go/lib/backend/k8s/conversion/constants.go b/libcalico-go/lib/backend/k8s/conversion/constants.go index f85032c52ac..c79e3c4739c 100644 --- a/libcalico-go/lib/backend/k8s/conversion/constants.go +++ b/libcalico-go/lib/backend/k8s/conversion/constants.go @@ -65,5 +65,5 @@ const ( AnnotationQoSEgressPacketBurst = "qos.projectcalico.org/egressPacketBurst" AnnotationQoSIngressMaxConnections = "qos.projectcalico.org/ingressMaxConnections" AnnotationQoSEgressMaxConnections = "qos.projectcalico.org/egressMaxConnections" - AnnotationQoSEgressDSCP = "qos.projectcalico.org/egressDSCP" + AnnotationQoSEgressDSCP = "qos.projectcalico.org/dscp" ) diff --git a/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go b/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go index 0a66cf56cc6..036e2173c79 100644 --- a/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go +++ b/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go @@ -531,8 +531,13 @@ func handleQoSControlsAnnotations(annotations map[string]string) (*libapiv3.QoSC // Calico DSCP value for egress traffic annotation. if str, found := annotations[AnnotationQoSEgressDSCP]; found { - value := numorstring.DSCPFromString(str) - qosControls.DSCP = &value + dscp := numorstring.DSCPFromString(str) + err := dscp.Validate() + if err != nil { + errs = append(errs, fmt.Errorf("error parsing DSCP annotation: %w", err)) + } else { + qosControls.DSCP = &dscp + } } // return nil if no control is configured From 74b2132826c11469eda0b58db12458e3036dd392 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Tue, 12 Aug 2025 08:52:45 -0700 Subject: [PATCH 06/15] fix --- felix/calc/event_sequencer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/felix/calc/event_sequencer_test.go b/felix/calc/event_sequencer_test.go index ba1832f3bbb..df71502ec5e 100644 --- a/felix/calc/event_sequencer_test.go +++ b/felix/calc/event_sequencer_test.go @@ -18,9 +18,9 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" + "github.com/projectcalico/api/pkg/lib/numorstring" googleproto "google.golang.org/protobuf/proto" - "github.com/projectcalico/api/pkg/lib/numorstring" "github.com/projectcalico/calico/felix/calc" "github.com/projectcalico/calico/felix/config" "github.com/projectcalico/calico/felix/proto" From 4df1027228e80b26fb6fe376c2ae03baee18d436 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Tue, 12 Aug 2025 10:45:27 -0700 Subject: [PATCH 07/15] Add UT for DSCP type --- api/pkg/lib/numorstring/dscp.go | 9 ++- api/pkg/lib/numorstring/numorstring_test.go | 78 +++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/api/pkg/lib/numorstring/dscp.go b/api/pkg/lib/numorstring/dscp.go index c56add15ac0..b7df027d571 100644 --- a/api/pkg/lib/numorstring/dscp.go +++ b/api/pkg/lib/numorstring/dscp.go @@ -83,7 +83,7 @@ func DSCPFromString(s string) DSCP { for k := range AllDSCPValues { if strings.EqualFold(k, s) { return DSCP( - Uint8OrString{Type: NumOrStringString, StrVal: s}, + Uint8OrString{Type: NumOrStringString, StrVal: k}, ) } } @@ -110,8 +110,11 @@ func (d *DSCP) ToUint8() uint8 { func (d *DSCP) Validate() error { // If a number, it must be between 0 and 63. val, err := (*Uint8OrString)(d).NumValue() - if err == nil && val > 63 { - return fmt.Errorf("DSCP must be between 0 and 63") + if err == nil { + if val > 63 { + return fmt.Errorf("DSCP must be between 0 and 63") + } + return nil } // Otherwise, it must be one of the known constant. diff --git a/api/pkg/lib/numorstring/numorstring_test.go b/api/pkg/lib/numorstring/numorstring_test.go index 1b589ea211c..3e9b78176f9 100644 --- a/api/pkg/lib/numorstring/numorstring_test.go +++ b/api/pkg/lib/numorstring/numorstring_test.go @@ -95,6 +95,7 @@ func init() { Entry("should accept 0 DSCP as int", "0", dscpType, numorstring.DSCPFromInt(0)), Entry("should accept 63 DSCP as int", "63", dscpType, numorstring.DSCPFromInt(63)), Entry("should accept DF DSCP as string", "\"DF\"", dscpType, numorstring.DSCPFromString(numorstring.DF)), + Entry("should reject bad DSCP string", "\"25", dscpType, nil), ) // Perform tests of JSON marshaling of the various field types. @@ -126,6 +127,11 @@ func init() { // Protocol tests. Entry("should marshal protocol of 0", numorstring.ProtocolFromInt(0), "0"), Entry("should marshal protocol of udp", numorstring.ProtocolFromString("UDP"), "\"UDP\""), + + // DSCP tests. + Entry("should marshal dscp of 0", numorstring.DSCPFromInt(0), "0"), + Entry("should marshal dscp of 120", numorstring.DSCPFromInt(120), "120"), + Entry("should marshal dscp of DF", numorstring.DSCPFromString("DF"), "\"DF\""), ) // Perform tests of Stringer interface various field types. @@ -146,6 +152,10 @@ func init() { // Protocol tests. Entry("should stringify protocol of 0", numorstring.ProtocolFromInt(0), "0"), Entry("should stringify protocol of udp", numorstring.ProtocolFromString("UDP"), "UDP"), + + // DSCP tests. + Entry("should stringify DSCP of 0", numorstring.ProtocolFromInt(0), "0"), + Entry("should stringify DSCP of AF22", numorstring.ProtocolFromString("AF22"), "AF22"), ) // Perform tests of Protocols supporting ports. @@ -196,6 +206,74 @@ func init() { Entry("protocol udp -> UDP", numorstring.ProtocolFromInt(2), numorstring.ProtocolFromInt(2)), Entry("protocol tcp -> TCP", numorstring.ProtocolFromString("TCP"), numorstring.ProtocolFromStringV1("TCP")), ) + + // Perform tests of DSCP FromString method. + DescribeTable("NumOrStringDSCP FromString is not case-sensitive", + func(input, expected string) { + Expect(numorstring.DSCPFromString(input).StrVal).To(Equal(expected), + "expected parsed dscp to match") + }, + Entry("dscp cs6 -> CS6", "cs6", "CS6"), + Entry("dscp Af11 -> AF11", "Af11", "AF11"), + Entry("dscp ef -> EF", "ef", "EF"), + Entry("unknown dscp xxxXXX", "xxxXXX", "xxxXXX"), + ) + + // Perform tests for DSCP ToUint8 method for straing values. + DescribeTable("NumOrStringDSCP ToUint8 returns valid values", + func(input string, expected int) { + dscp := numorstring.DSCPFromString(input) + Expect(dscp.ToUint8()).To(Equal(uint8(expected)), + "expect parsed dscp to match") + }, + Entry("dscp BE", "BE", 0), + Entry("dscp AF33", "AF33", 30), + Entry("dscp CS5", "CS5", 40), + ) + + // Perform tests for DSCP validation for string values. + DescribeTable("NumOrStringDSCP Validate method validates string inputs correctly", + func(input string, valid bool) { + dscp := numorstring.DSCPFromString(input) + err := dscp.Validate() + if valid { + Expect(err).To(BeNil(), "expect validate to not return error") + } else { + Expect(err).ToNot(BeNil(), "expect validate to return error") + } + }, + Entry("should accept EF", "EF", true), + Entry("should accept AF11", "AF11", true), + Entry("should accept CS2", "CS2", true), + Entry("should accept 0", "0", true), + Entry("should accept 40", "40", true), + Entry("should accept 63", "63", true), + Entry("should reject 64", "64", false), + Entry("should reject 120", "120", false), + Entry("should reject -1", "-1", false), + Entry("should reject CS9", "CS9", false), + Entry("should reject xxx", "xxx", false), + Entry("should reject empty string", "", false), + Entry("should reject empty string", " ", false), + ) + + // Perform tests for DSCP validation for numerical values. + DescribeTable("NumOrStringDSCP Validate method validates numerical inputs correctly", + func(input int, valid bool) { + dscp := numorstring.DSCPFromInt(uint8(input)) + err := dscp.Validate() + if valid { + Expect(err).To(BeNil(), "expect validate to not return error") + } else { + Expect(err).ToNot(BeNil(), "expect validate to return error") + } + }, + Entry("should accept 0", 0, true), + Entry("should accept 40", 40, true), + Entry("should accept 63", 63, true), + Entry("should reject 64", 64, false), + Entry("should reject 120", 120, false), + ) } func portFromRange(minPort, maxPort uint16) numorstring.Port { From 739c28f7025e6ad75b76684bbe340e8e8607df2e Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Thu, 14 Aug 2025 19:26:46 -0700 Subject: [PATCH 08/15] First commit --- felix/dataplane/linux/int_dataplane.go | 6 ++++++ felix/dataplane/linux/qos_policy_mgr.go | 7 ++++--- felix/generictables/match_builder.go | 1 + felix/iptables/match_builder.go | 5 +++++ felix/nftables/match_builder.go | 5 +++++ felix/rules/qos.go | 21 +++++++++++++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) diff --git a/felix/dataplane/linux/int_dataplane.go b/felix/dataplane/linux/int_dataplane.go index 15ee887811e..ff0d584339b 100644 --- a/felix/dataplane/linux/int_dataplane.go +++ b/felix/dataplane/linux/int_dataplane.go @@ -1120,6 +1120,12 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { dp.endpointsSourceV4 = epManager dp.RegisterManager(newFloatingIPManager(natTableV4, ruleRenderer, 4, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV4, natTableV4, ruleRenderer, config.MaxIPSetSize, 4)) + + var filterMapsV6 nftables.MapsDataplane + if config.RulesConfig.NFTables { + filterMapsV6 = filterTableV6.(nftables.MapsDataplane) + } + dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) if config.RulesConfig.IPIPEnabled { diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go index 1446517e435..0776cd7cf67 100644 --- a/felix/dataplane/linux/qos_policy_mgr.go +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -28,11 +28,12 @@ import ( type qosPolicyManager struct { ipVersion uint8 ruleRenderer rules.RuleRenderer + mangleTable Table + forNftables bool // QoS policy - mangleTable Table - dirty bool - policies map[types.WorkloadEndpointID]rules.QoSPolicy + dirty bool + policies map[types.WorkloadEndpointID]rules.QoSPolicy logCxt *logrus.Entry } diff --git a/felix/generictables/match_builder.go b/felix/generictables/match_builder.go index 45382cb3102..15e236442e5 100644 --- a/felix/generictables/match_builder.go +++ b/felix/generictables/match_builder.go @@ -75,6 +75,7 @@ type MatchCriteria interface { // Only supported in nftables. InInterfaceVMAP(mapname string) MatchCriteria OutInterfaceVMAP(mapname string) MatchCriteria + SourceNetVMAP(mapname string) MatchCriteria } type AddrType string diff --git a/felix/iptables/match_builder.go b/felix/iptables/match_builder.go index a57011f2a7f..5b628fe6098 100644 --- a/felix/iptables/match_builder.go +++ b/felix/iptables/match_builder.go @@ -335,6 +335,11 @@ func (m matchCriteria) OutInterfaceVMAP(mapname string) generictables.MatchCrite return m } +func (m matchCriteria) SourceNetVMAP(_ string) generictables.MatchCriteria { + log.Panic("SourceNetVMAP not supported in iptables") + return m +} + func PortsToMultiport(ports []uint16) string { portFragments := make([]string, len(ports)) for i, port := range ports { diff --git a/felix/nftables/match_builder.go b/felix/nftables/match_builder.go index e206c5d6adf..b7a5b9a1058 100644 --- a/felix/nftables/match_builder.go +++ b/felix/nftables/match_builder.go @@ -544,6 +544,11 @@ func (m nftMatch) OutInterfaceVMAP(name string) generictables.MatchCriteria { return m } +func (m nftMatch) SourceNetVMAP(name string) generictables.MatchCriteria { + m.clauses = append(m.clauses, fmt.Sprintf(" saddr vmap @-%s", LegalizeSetName(name))) + return m +} + // PortsToMultiport converts a list of ports to a multiport set suitable for inline use in nftables rules. func PortsToMultiport(ports []uint16) string { portFragments := make([]string, len(ports)) diff --git a/felix/rules/qos.go b/felix/rules/qos.go index 833bf35228a..a731e64da76 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -24,6 +24,27 @@ type QoSPolicy struct { } func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []QoSPolicy, ipVersion uint8) *generictables.Chain { + if r.NFTables { + return r.nftablesQoSPolicyRules(policies, ipVersion) + } + return r.defaultQoSPolicyRules(policies, ipVersion) +} + +func (r *DefaultRuleRenderer) nftablesQoSPolicyRules(policies []QoSPolicy, ipVersion uint8) *generictables.Chain { + var rules []generictables.Rule + // Policies is sorted and validated by QoS policy manager. + + rules = append(rules, generictables.Rule{ + Match: r.NewMatch().SourceNetVMAP("some map"), + }) + + return &generictables.Chain{ + Name: ChainQoSPolicy, + Rules: rules, + } +} + +func (r *DefaultRuleRenderer) defaultQoSPolicyRules(policies []QoSPolicy, ipVersion uint8) *generictables.Chain { var rules []generictables.Rule // Policies is sorted and validated by QoS policy manager. for _, p := range policies { From 48ae3669c60126fa676c9bcf73756797f58164a4 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Fri, 15 Aug 2025 10:09:25 -0700 Subject: [PATCH 09/15] more --- felix/dataplane/linux/int_dataplane.go | 13 +++++++++---- felix/dataplane/linux/qos_policy_mgr.go | 22 +++++++++++++++++++++- felix/nftables/maps.go | 5 ++++- felix/rules/qos.go | 2 +- felix/rules/rule_defs.go | 3 ++- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/felix/dataplane/linux/int_dataplane.go b/felix/dataplane/linux/int_dataplane.go index ff0d584339b..0ee0aff6776 100644 --- a/felix/dataplane/linux/int_dataplane.go +++ b/felix/dataplane/linux/int_dataplane.go @@ -1121,12 +1121,12 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { dp.RegisterManager(newFloatingIPManager(natTableV4, ruleRenderer, 4, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV4, natTableV4, ruleRenderer, config.MaxIPSetSize, 4)) - var filterMapsV6 nftables.MapsDataplane + var mangleMaps nftables.MapsDataplane if config.RulesConfig.NFTables { - filterMapsV6 = filterTableV6.(nftables.MapsDataplane) + mangleMaps = mangleTableV4.(nftables.MapsDataplane) } - dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) + dp.RegisterManager(newQoSPolicyManager(mangleTableV4, mangleMaps, ruleRenderer, 4)) if config.RulesConfig.IPIPEnabled { log.Info("IPIP enabled, starting thread to keep tunnel configuration in sync.") @@ -1323,9 +1323,14 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { )) dp.RegisterManager(newFloatingIPManager(natTableV6, ruleRenderer, 6, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV6, natTableV6, ruleRenderer, config.MaxIPSetSize, 6)) - dp.RegisterManager(newQoSPolicyManager(mangleTableV6, ruleRenderer, 6)) dp.RegisterManager(newServiceLoopManager(filterTableV6, ruleRenderer, 6)) + var mangleMapsV6 nftables.MapsDataplane + if config.RulesConfig.NFTables { + mangleMaps = mangleTableV6.(nftables.MapsDataplane) + } + dp.RegisterManager(newQoSPolicyManager(mangleTableV6, mangleMapsV6, ruleRenderer, 6)) + // Add a manager for IPv6 wireguard configuration. This is added irrespective of whether wireguard is actually enabled // because it may need to tidy up some of the routing rules when disabled. cryptoRouteTableWireguardV6 := wireguard.New(config.Hostname, &config.Wireguard, 6, config.NetlinkTimeout, diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go index 0776cd7cf67..bff38ac11bf 100644 --- a/felix/dataplane/linux/qos_policy_mgr.go +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -15,11 +15,13 @@ package intdataplane import ( + "fmt" "sort" "strings" "github.com/sirupsen/logrus" + "github.com/projectcalico/calico/felix/nftables" "github.com/projectcalico/calico/felix/proto" "github.com/projectcalico/calico/felix/rules" "github.com/projectcalico/calico/felix/types" @@ -27,8 +29,9 @@ import ( type qosPolicyManager struct { ipVersion uint8 - ruleRenderer rules.RuleRenderer mangleTable Table + mangleMaps nftables.MapsDataplane + ruleRenderer rules.RuleRenderer forNftables bool // QoS policy @@ -40,6 +43,7 @@ type qosPolicyManager struct { func newQoSPolicyManager( mangleTable Table, + mangleMaps nftables.MapsDataplane, ruleRenderer rules.RuleRenderer, ipVersion uint8, ) *qosPolicyManager { @@ -48,6 +52,7 @@ func newQoSPolicyManager( policies: map[types.WorkloadEndpointID]rules.QoSPolicy{}, dirty: true, mangleTable: mangleTable, + mangleMaps: mangleMaps, ruleRenderer: ruleRenderer, logCxt: logrus.WithField("ipVersion", ipVersion), } @@ -112,6 +117,13 @@ func (m *qosPolicyManager) CompleteDeferredWork() error { return policies[i].SrcAddrs < policies[j].SrcAddrs }) + if m.mangleMaps != nil { + mappings := nftablesVMappings(policies) + mapMeta := nftables.MapMetadata{Name: rules.NftablesQoSPolicyMap, Type: } + m.mangleMaps.AddOrReplaceMap() + + } + chain := m.ruleRenderer.EgressQoSPolicyChain(policies, m.ipVersion) m.mangleTable.UpdateChain(chain) m.dirty = false @@ -119,3 +131,11 @@ func (m *qosPolicyManager) CompleteDeferredWork() error { return nil } + +func nftablesVMappings(policies []rules.QoSPolicy) map[string][]string { + mappings := map[string][]string{} + for _, p := range policies { + mappings[p.SrcAddrs] = []string{fmt.Sprintf("dscp %d", p.DSCP)} + } + return mappings +} diff --git a/felix/nftables/maps.go b/felix/nftables/maps.go index f7743a5ff52..e9406f6a7cb 100644 --- a/felix/nftables/maps.go +++ b/felix/nftables/maps.go @@ -38,7 +38,10 @@ var gaugeVecNumMaps = prometheus.NewGaugeVec(prometheus.GaugeOpts{ type MapType string -const MapTypeInterfaceMatch MapType = "interfaceMatch" +const ( + MapTypeInterfaceMatch MapType = "interfaceMatch" + MapTypeSourceNetMatch MapType = "sourceNetMatch" +) type MapsDataplane interface { AddOrReplaceMap(meta MapMetadata, members map[string][]string) diff --git a/felix/rules/qos.go b/felix/rules/qos.go index a731e64da76..b25e52075b3 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -35,7 +35,7 @@ func (r *DefaultRuleRenderer) nftablesQoSPolicyRules(policies []QoSPolicy, ipVer // Policies is sorted and validated by QoS policy manager. rules = append(rules, generictables.Rule{ - Match: r.NewMatch().SourceNetVMAP("some map"), + Match: r.NewMatch().SourceNetVMAP("qosmap"), }) return &generictables.Chain{ diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index 7a2b19479d9..f1e9872f4f3 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -61,7 +61,8 @@ const ( ChainManglePrerouting = ChainNamePrefix + "PREROUTING" ChainManglePostrouting = ChainNamePrefix + "POSTROUTING" - ChainQoSPolicy = ChainNamePrefix + "qos-policy" + ChainQoSPolicy = ChainNamePrefix + "qos-policy" + NftablesQoSPolicyMap = ChainNamePrefix + "qos-policy" IPSetIDAllPools = "all-ipam-pools" IPSetIDNATOutgoingMasqPools = "masq-ipam-pools" From 18f50fabf67faf97e922ce031363fb3ec871127f Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Fri, 15 Aug 2025 16:35:12 -0700 Subject: [PATCH 10/15] Fix --- felix/dataplane/linux/qos_policy_mgr.go | 2 +- felix/generictables/actions.go | 2 +- felix/iptables/actions.go | 2 +- felix/iptables/actions_test.go | 2 +- felix/nftables/actions.go | 13 ++++--------- felix/nftables/actions_test.go | 4 ++-- felix/rules/qos.go | 4 ++-- felix/rules/qos_test.go | 13 +++---------- felix/rules/rule_defs.go | 2 +- .../lib/backend/k8s/conversion/conversion_test.go | 5 ++++- 10 files changed, 20 insertions(+), 29 deletions(-) diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go index 1446517e435..4178dbd9d28 100644 --- a/felix/dataplane/linux/qos_policy_mgr.go +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -111,7 +111,7 @@ func (m *qosPolicyManager) CompleteDeferredWork() error { return policies[i].SrcAddrs < policies[j].SrcAddrs }) - chain := m.ruleRenderer.EgressQoSPolicyChain(policies, m.ipVersion) + chain := m.ruleRenderer.EgressQoSPolicyChain(policies) m.mangleTable.UpdateChain(chain) m.dirty = false } diff --git a/felix/generictables/actions.go b/felix/generictables/actions.go index 99f6b9cb809..7a1a3de76b5 100644 --- a/felix/generictables/actions.go +++ b/felix/generictables/actions.go @@ -35,7 +35,7 @@ type ActionFactory interface { Nflog(group uint16, prefix string, size int) Action LimitPacketRate(rate int64, burst int64, mark uint32) Action LimitNumConnections(num int64, rejectWith RejectWith) Action - DSCP(value, ipVersion uint8) Action + DSCP(value uint8) Action } type RejectWith string diff --git a/felix/iptables/actions.go b/felix/iptables/actions.go index a383114a1d6..55fa73adf46 100644 --- a/felix/iptables/actions.go +++ b/felix/iptables/actions.go @@ -121,7 +121,7 @@ func (a *actionFactory) LimitNumConnections(num int64, rejectWith generictables. } } -func (a *actionFactory) DSCP(value uint8, _ uint8) generictables.Action { +func (a *actionFactory) DSCP(value uint8) generictables.Action { return DSCPAction{ Value: value, } diff --git a/felix/iptables/actions_test.go b/felix/iptables/actions_test.go index 6d77615d5ac..28c2e8b2fda 100644 --- a/felix/iptables/actions_test.go +++ b/felix/iptables/actions_test.go @@ -50,6 +50,6 @@ var _ = DescribeTable("Actions", Entry("RestoreConnMarkAction", environment.Features{}, RestoreConnMarkAction{}, "--jump CONNMARK --restore-mark --mask 0xffffffff"), Entry("LimitPacketRateAction", environment.Features{}, LimitPacketRateAction{Rate: 1000, Burst: 5, Mark: 0x200}, "-m limit --limit 1000/sec --limit-burst 5 --jump MARK --set-mark 0x200/0x200"), Entry("LimitNumConnectionsAction", environment.Features{}, LimitNumConnectionsAction{Num: 10, RejectWith: generictables.RejectWithTCPReset}, "-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 10 --connlimit-mask 0 -j REJECT --reject-with tcp-reset"), - Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 16}, "--jump DSCP --set-dscp 16"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 0}, "--jump DSCP --set-dscp 0"), Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 20}, "--jump DSCP --set-dscp 20"), ) diff --git a/felix/nftables/actions.go b/felix/nftables/actions.go index f3f83475fbd..cd135f116ae 100644 --- a/felix/nftables/actions.go +++ b/felix/nftables/actions.go @@ -134,10 +134,9 @@ func (a *actionSet) LimitNumConnections(num int64, rejectWith generictables.Reje } } -func (a *actionSet) DSCP(value, ipVersion uint8) generictables.Action { +func (a *actionSet) DSCP(value uint8) generictables.Action { return DSCPAction{ - Value: value, - IpVersion: ipVersion, + Value: value, } } @@ -514,15 +513,11 @@ func (a LimitNumConnectionsAction) String() string { } type DSCPAction struct { - Value uint8 - IpVersion uint8 + Value uint8 } func (a DSCPAction) ToFragment(features *environment.Features) string { - if a.IpVersion == 6 { - return fmt.Sprintf("ip6 dscp set %d", a.Value) - } - return fmt.Sprintf("ip dscp set %d", a.Value) + return fmt.Sprintf(" dscp set %d", a.Value) } func (a DSCPAction) String() string { diff --git a/felix/nftables/actions_test.go b/felix/nftables/actions_test.go index 9859a037f2e..c830a9406f6 100644 --- a/felix/nftables/actions_test.go +++ b/felix/nftables/actions_test.go @@ -48,6 +48,6 @@ var _ = DescribeTable("Actions", Entry("SetConnMarkAction", environment.Features{}, SetConnMarkAction{Mark: 0x1000, Mask: 0xf000}, "ct mark set ct mark & 0xffff0fff ^ 0x1000"), Entry("LimitPacketRateAction", environment.Features{}, LimitPacketRateAction{Rate: 1000, Burst: 5}, "limit rate over 1000/second burst 5 packets drop"), Entry("LimitNumConnectionsAction", environment.Features{}, LimitNumConnectionsAction{Num: 10, RejectWith: generictables.RejectWithTCPReset}, "ct count over 10 reject with tcp reset"), - Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 16, IpVersion: 4}, "ip dscp set 16"), - Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 20, IpVersion: 6}, "ip6 dscp set 20"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 0}, " dscp set 0"), + Entry("DSCPAction", environment.Features{}, DSCPAction{Value: 20}, " dscp set 20"), ) diff --git a/felix/rules/qos.go b/felix/rules/qos.go index 833bf35228a..da19252160b 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -23,13 +23,13 @@ type QoSPolicy struct { DSCP uint8 } -func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []QoSPolicy, ipVersion uint8) *generictables.Chain { +func (r *DefaultRuleRenderer) EgressQoSPolicyChain(policies []QoSPolicy) *generictables.Chain { var rules []generictables.Rule // Policies is sorted and validated by QoS policy manager. for _, p := range policies { rules = append(rules, generictables.Rule{ Match: r.NewMatch().SourceNet(p.SrcAddrs), - Action: r.DSCP(p.DSCP, ipVersion), + Action: r.DSCP(p.DSCP), }) } diff --git a/felix/rules/qos_test.go b/felix/rules/qos_test.go index ee6ff3ccc08..bcd76526288 100644 --- a/felix/rules/qos_test.go +++ b/felix/rules/qos_test.go @@ -40,14 +40,7 @@ var _ = Describe("QoS", func() { }) It("should render empty chain for no policies", func() { - Expect(renderer.EgressQoSPolicyChain([]QoSPolicy{}, 4)).To(Equal(&generictables.Chain{ - Name: "cali-qos-policy", - Rules: nil, - })) - }) - - It("should render empty IPv6 chain for no policies", func() { - Expect(renderer.EgressQoSPolicyChain(nil, 6)).To(Equal(&generictables.Chain{ + Expect(renderer.EgressQoSPolicyChain([]QoSPolicy{})).To(Equal(&generictables.Chain{ Name: "cali-qos-policy", Rules: nil, })) @@ -59,7 +52,7 @@ var _ = Describe("QoS", func() { {SrcAddrs: "192.168.10.100,172.17.1.100", DSCP: 40}, {SrcAddrs: "192.168.20.1", DSCP: 0}, } - Expect(renderer.EgressQoSPolicyChain(policies, 4)).To(Equal(&generictables.Chain{ + Expect(renderer.EgressQoSPolicyChain(policies)).To(Equal(&generictables.Chain{ Name: "cali-qos-policy", Rules: []generictables.Rule{ { @@ -84,7 +77,7 @@ var _ = Describe("QoS", func() { {SrcAddrs: "dead:beef::1:100,dead:beef::10:1", DSCP: 40}, {SrcAddrs: "dead:beef::2:2", DSCP: 22}, } - Expect(renderer.EgressQoSPolicyChain(policies, 6)).To(Equal(&generictables.Chain{ + Expect(renderer.EgressQoSPolicyChain(policies)).To(Equal(&generictables.Chain{ Name: "cali-qos-policy", Rules: []generictables.Rule{ { diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index 7a2b19479d9..f4aac5c7c02 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -322,7 +322,7 @@ type RuleRenderer interface { NATOutgoingChain(active bool, ipVersion uint8) *generictables.Chain - EgressQoSPolicyChain(policies []QoSPolicy, ipVersion uint8) *generictables.Chain + EgressQoSPolicyChain(policies []QoSPolicy) *generictables.Chain DNATsToIptablesChains(dnats map[string]string) []*generictables.Chain SNATsToIptablesChains(snats map[string]string) []*generictables.Chain diff --git a/libcalico-go/lib/backend/k8s/conversion/conversion_test.go b/libcalico-go/lib/backend/k8s/conversion/conversion_test.go index 86254811b9e..5ab1a5bbb1d 100644 --- a/libcalico-go/lib/backend/k8s/conversion/conversion_test.go +++ b/libcalico-go/lib/backend/k8s/conversion/conversion_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 Tigera, Inc. All rights reserved. +// Copyright (c) 2016-2025 Tigera, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -1195,6 +1195,7 @@ var _ = Describe("Test Pod conversion", func() { }) It("should parse valid QoSControl annotations", func() { + dscp := numorstring.DSCPFromString("cs5") pod := kapiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "podA", @@ -1215,6 +1216,7 @@ var _ = Describe("Test Pod conversion", func() { "qos.projectcalico.org/egressPacketBurst": "10k", "qos.projectcalico.org/ingressMaxConnections": "13M", "qos.projectcalico.org/egressMaxConnections": "14M", + "qos.projectcalico.org/dscp": "cs5", }, Labels: map[string]string{ "labelA": "valueA", @@ -1246,6 +1248,7 @@ var _ = Describe("Test Pod conversion", func() { EgressPacketBurst: 10000, IngressMaxConnections: 13000000, EgressMaxConnections: 14000000, + DSCP: &dscp, } Expect(wep.Value.(*libapiv3.WorkloadEndpoint).Spec.QoSControls).To(BeEquivalentTo(expectedQoSControls)) }) From 61ce4bef7cd52c6ddd635b67b1ad56a9dba32831 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Mon, 18 Aug 2025 11:32:49 -0700 Subject: [PATCH 11/15] do not enable in bpf --- felix/dataplane/linux/int_dataplane.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/felix/dataplane/linux/int_dataplane.go b/felix/dataplane/linux/int_dataplane.go index 15ee887811e..a64b3f06173 100644 --- a/felix/dataplane/linux/int_dataplane.go +++ b/felix/dataplane/linux/int_dataplane.go @@ -1120,7 +1120,10 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { dp.endpointsSourceV4 = epManager dp.RegisterManager(newFloatingIPManager(natTableV4, ruleRenderer, 4, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV4, natTableV4, ruleRenderer, config.MaxIPSetSize, 4)) - dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) + + if !config.BPFEnabled { + dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) + } if config.RulesConfig.IPIPEnabled { log.Info("IPIP enabled, starting thread to keep tunnel configuration in sync.") @@ -1317,9 +1320,12 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { )) dp.RegisterManager(newFloatingIPManager(natTableV6, ruleRenderer, 6, config.FloatingIPsEnabled)) dp.RegisterManager(newMasqManager(ipSetsV6, natTableV6, ruleRenderer, config.MaxIPSetSize, 6)) - dp.RegisterManager(newQoSPolicyManager(mangleTableV6, ruleRenderer, 6)) dp.RegisterManager(newServiceLoopManager(filterTableV6, ruleRenderer, 6)) + if !config.BPFEnabled { + dp.RegisterManager(newQoSPolicyManager(mangleTableV6, ruleRenderer, 6)) + } + // Add a manager for IPv6 wireguard configuration. This is added irrespective of whether wireguard is actually enabled // because it may need to tidy up some of the routing rules when disabled. cryptoRouteTableWireguardV6 := wireguard.New(config.Hostname, &config.Wireguard, 6, config.NetlinkTimeout, From 039dc5646172f8d4e6600ef65744dd0610d62e00 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Tue, 19 Aug 2025 17:05:08 -0700 Subject: [PATCH 12/15] more --- felix/dataplane/linux/int_dataplane.go | 4 ++-- felix/dataplane/linux/qos_policy_mgr.go | 7 +++--- felix/fv/qos_policy_test.go | 5 ++-- felix/generictables/actions.go | 2 +- felix/iptables/actions.go | 8 +++---- felix/nftables/actions.go | 7 ++++-- felix/nftables/maps.go | 32 +++++++++++++++++++++++-- felix/nftables/match_builder.go | 3 ++- felix/nftables/table_layer.go | 14 ++++++++--- felix/rules/qos.go | 8 +++++-- 10 files changed, 67 insertions(+), 23 deletions(-) diff --git a/felix/dataplane/linux/int_dataplane.go b/felix/dataplane/linux/int_dataplane.go index 9fd60a6e6ab..dcc90662728 100644 --- a/felix/dataplane/linux/int_dataplane.go +++ b/felix/dataplane/linux/int_dataplane.go @@ -1126,7 +1126,7 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { if config.RulesConfig.NFTables { mangleMaps = mangleTableV4.(nftables.MapsDataplane) } - dp.RegisterManager(newQoSPolicyManager(mangleTableV4, ruleRenderer, 4)) + dp.RegisterManager(newQoSPolicyManager(mangleTableV4, mangleMaps, ruleRenderer, 4)) } if config.RulesConfig.IPIPEnabled { @@ -1331,7 +1331,7 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { if config.RulesConfig.NFTables { mangleMapsV6 = mangleTableV6.(nftables.MapsDataplane) } - dp.RegisterManager(newQoSPolicyManager(mangleTableV6, ruleRenderer, 6)) + dp.RegisterManager(newQoSPolicyManager(mangleTableV6, mangleMapsV6, ruleRenderer, 6)) } // Add a manager for IPv6 wireguard configuration. This is added irrespective of whether wireguard is actually enabled diff --git a/felix/dataplane/linux/qos_policy_mgr.go b/felix/dataplane/linux/qos_policy_mgr.go index 8c90e1f31a1..a54a8c45f46 100644 --- a/felix/dataplane/linux/qos_policy_mgr.go +++ b/felix/dataplane/linux/qos_policy_mgr.go @@ -119,9 +119,8 @@ func (m *qosPolicyManager) CompleteDeferredWork() error { if m.mangleMaps != nil { mappings := nftablesVMappings(policies) - mapMeta := nftables.MapMetadata{Name: rules.NftablesQoSPolicyMap, Type: } - m.mangleMaps.AddOrReplaceMap() - + mapMeta := nftables.MapMetadata{Name: rules.NftablesQoSPolicyMap, Type: nftables.MapTypeSourceNetMatch} + m.mangleMaps.AddOrReplaceMap(mapMeta, mappings) } chain := m.ruleRenderer.EgressQoSPolicyChain(policies) @@ -135,7 +134,7 @@ func (m *qosPolicyManager) CompleteDeferredWork() error { func nftablesVMappings(policies []rules.QoSPolicy) map[string][]string { mappings := map[string][]string{} for _, p := range policies { - mappings[p.SrcAddrs] = []string{fmt.Sprintf("dscp %d", p.DSCP)} + mappings[p.SrcAddrs] = []string{fmt.Sprintf("%d", p.DSCP)} } return mappings } diff --git a/felix/fv/qos_policy_test.go b/felix/fv/qos_policy_test.go index 3440bf89f4e..f6308dee0f7 100644 --- a/felix/fv/qos_policy_test.go +++ b/felix/fv/qos_policy_test.go @@ -35,7 +35,7 @@ import ( api "github.com/projectcalico/calico/libcalico-go/lib/apis/v3" ) -var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apiconfig.DatastoreType{apiconfig.EtcdV3, apiconfig.Kubernetes}, func(getInfra infrastructure.InfraFactory) { +var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ pepper qos policy tests", []apiconfig.DatastoreType{apiconfig.EtcdV3, apiconfig.Kubernetes}, func(getInfra infrastructure.InfraFactory) { const ( wepPortStr = "8055" ) @@ -169,7 +169,8 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apicon } }) - It("applying DSCP annotation should result is adding correct rules", func() { + It("pepper1 applying DSCP annotation should result is adding correct rules", func() { + time.Sleep(time.Minute * 20) dscp0 := numorstring.DSCPFromInt(0) // 0x0 dscp20 := numorstring.DSCPFromInt(20) // 0x14 dscp32 := numorstring.DSCPFromInt(32) // 0x20 diff --git a/felix/generictables/actions.go b/felix/generictables/actions.go index 7a1a3de76b5..e824ef9ff3b 100644 --- a/felix/generictables/actions.go +++ b/felix/generictables/actions.go @@ -35,7 +35,7 @@ type ActionFactory interface { Nflog(group uint16, prefix string, size int) Action LimitPacketRate(rate int64, burst int64, mark uint32) Action LimitNumConnections(num int64, rejectWith RejectWith) Action - DSCP(value uint8) Action + DSCP(value string) Action } type RejectWith string diff --git a/felix/iptables/actions.go b/felix/iptables/actions.go index 55fa73adf46..71b0bea1676 100644 --- a/felix/iptables/actions.go +++ b/felix/iptables/actions.go @@ -121,7 +121,7 @@ func (a *actionFactory) LimitNumConnections(num int64, rejectWith generictables. } } -func (a *actionFactory) DSCP(value uint8) generictables.Action { +func (a *actionFactory) DSCP(value string) generictables.Action { return DSCPAction{ Value: value, } @@ -479,13 +479,13 @@ func (a LimitNumConnectionsAction) String() string { } type DSCPAction struct { - Value uint8 + Value string } func (a DSCPAction) ToFragment(features *environment.Features) string { - return fmt.Sprintf("--jump DSCP --set-dscp %d", a.Value) + return fmt.Sprintf("--jump DSCP --set-dscp %s", a.Value) } func (a DSCPAction) String() string { - return fmt.Sprintf("DSCP %d", a.Value) + return fmt.Sprintf("DSCP %s", a.Value) } diff --git a/felix/nftables/actions.go b/felix/nftables/actions.go index cd135f116ae..5f4e5026cde 100644 --- a/felix/nftables/actions.go +++ b/felix/nftables/actions.go @@ -134,7 +134,7 @@ func (a *actionSet) LimitNumConnections(num int64, rejectWith generictables.Reje } } -func (a *actionSet) DSCP(value uint8) generictables.Action { +func (a *actionSet) DSCP(value string) generictables.Action { return DSCPAction{ Value: value, } @@ -513,10 +513,13 @@ func (a LimitNumConnectionsAction) String() string { } type DSCPAction struct { - Value uint8 + Value string } func (a DSCPAction) ToFragment(features *environment.Features) string { + if a.Value == "vmap" { + return "ip dscp" + } return fmt.Sprintf(" dscp set %d", a.Value) } diff --git a/felix/nftables/maps.go b/felix/nftables/maps.go index e9406f6a7cb..257df6588a8 100644 --- a/felix/nftables/maps.go +++ b/felix/nftables/maps.go @@ -377,7 +377,7 @@ func (s *Maps) LoadDataplaneState() error { for _, e := range mapData.elems { logCxt.WithField("element", e).Debug("Processing element") switch metadata.Type { - case MapTypeInterfaceMatch: + case MapTypeInterfaceMatch, MapTypeSourceNetMatch: strElems[e.Key[0]] = e.Value default: unknownElems.Add(UnknownMapMember(e.Key, e.Value)) @@ -445,7 +445,7 @@ func (s *Maps) NFTablesMap(name string) *knftables.Map { var flags []knftables.SetFlag switch metadata.Type { - case MapTypeInterfaceMatch: + case MapTypeInterfaceMatch, MapTypeSourceNetMatch: default: logrus.WithField("type", metadata.Type).Panic("Unexpected map type") } @@ -626,12 +626,32 @@ func CanonicaliseMapMember(mtype MapType, key string, value []string) MapMember } // An action and a chain. return interfaceToChain{key, splits[0], splits[1]} + case MapTypeSourceNetMatch: + return sourceNetToAction{source: key, action: value[0]} default: logrus.Errorf("Unknown map type: %v", mtype) } return nil } +// sourceNetToAction is a MapMember that represents a mapping from a source net to an terminal action. +type sourceNetToAction struct { + source string + action string +} + +func (m sourceNetToAction) Key() []string { + return []string{m.source} +} + +func (m sourceNetToAction) Value() []string { + return []string{m.action} +} + +func (m sourceNetToAction) String() string { + return fmt.Sprintf("%s -> %s", m.source, m.action) +} + // interfaceToAction is a MapMember that represents a mapping from an interface to an terminal action. type interfaceToAction struct { iface string @@ -673,6 +693,14 @@ func mapType(t MapType, ipVersion int) string { switch t { case MapTypeInterfaceMatch: return "ifname : verdict" + case MapTypeSourceNetMatch: + if ipVersion == 4 { + return "ipv4_addr : dscp" + //return "ipv4_addr : verdict" + } else { + return "ipv6_addr : dscp" + //return "ipv6_addr : verdict" + } default: logrus.WithField("type", string(t)).Panic("Unknown MapType") } diff --git a/felix/nftables/match_builder.go b/felix/nftables/match_builder.go index b7a5b9a1058..cd2516279ec 100644 --- a/felix/nftables/match_builder.go +++ b/felix/nftables/match_builder.go @@ -545,7 +545,8 @@ func (m nftMatch) OutInterfaceVMAP(name string) generictables.MatchCriteria { } func (m nftMatch) SourceNetVMAP(name string) generictables.MatchCriteria { - m.clauses = append(m.clauses, fmt.Sprintf(" saddr vmap @-%s", LegalizeSetName(name))) + //return fmt.Sprintf(" dscp set %d", a.Value) + m.clauses = append(m.clauses, fmt.Sprintf(" dscp set ip saddr map @-%s", LegalizeSetName(name))) return m } diff --git a/felix/nftables/table_layer.go b/felix/nftables/table_layer.go index b440d0a5b7f..2ba553c3082 100644 --- a/felix/nftables/table_layer.go +++ b/felix/nftables/table_layer.go @@ -86,12 +86,20 @@ func (t *tableLayer) namespaceMapMember(m []string) []string { return m } + action := strings.Split(strings.TrimSpace(m[0]), " ")[0] + // TODO: We only use "goto" in map members right now. If we add other actions, we'll need to namespace them. // This is a very brittle implementation that assumes that the map member is a single string that starts with "goto ". - if !strings.HasPrefix(m[0], "goto ") { - logrus.Panicf("Unexpected map member: %s", m) + switch action { + case "goto": + return []string{fmt.Sprintf("goto %s", t.namespaceName(m[0][5:]))} + case "dscp": + return m + //default: + // logrus.Panicf("Unexpected map member: %s", m) } - return []string{fmt.Sprintf("goto %s", t.namespaceName(m[0][5:]))} + + return m } func (t *tableLayer) Name() string { diff --git a/felix/rules/qos.go b/felix/rules/qos.go index c88f9ad11dd..ed89e5697c5 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -15,6 +15,8 @@ package rules import ( + "strconv" + "github.com/projectcalico/calico/felix/generictables" ) @@ -35,7 +37,9 @@ func (r *DefaultRuleRenderer) nftablesQoSPolicyRules(policies []QoSPolicy) *gene // Policies is sorted and validated by QoS policy manager. rules = append(rules, generictables.Rule{ - Match: r.NewMatch().SourceNetVMAP("qosmap"), + Match: r.NewMatch().SourceNetVMAP(NftablesQoSPolicyMap), + //Match: r.NewMatch(), + //Action: r.DSCP("vmap"), }) return &generictables.Chain{ @@ -50,7 +54,7 @@ func (r *DefaultRuleRenderer) defaultQoSPolicyRules(policies []QoSPolicy) *gener for _, p := range policies { rules = append(rules, generictables.Rule{ Match: r.NewMatch().SourceNet(p.SrcAddrs), - Action: r.DSCP(p.DSCP), + Action: r.DSCP(strconv.FormatUint(uint64(p.DSCP), 10)), }) } From e6c664268ce0c790e98efdfc3ed13bc020dcccea Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Thu, 21 Aug 2025 11:17:20 -0700 Subject: [PATCH 13/15] cleanup --- felix/dataplane/linux/qos_policy_mgr_test.go | 3 ++- felix/generictables/actions.go | 2 +- felix/iptables/actions.go | 8 ++++---- felix/nftables/actions.go | 10 ++++------ felix/rules/qos.go | 4 +--- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/felix/dataplane/linux/qos_policy_mgr_test.go b/felix/dataplane/linux/qos_policy_mgr_test.go index faed4e7b10d..7199a19a0c3 100644 --- a/felix/dataplane/linux/qos_policy_mgr_test.go +++ b/felix/dataplane/linux/qos_policy_mgr_test.go @@ -45,7 +45,8 @@ func qosPolicyManagerTests(ipVersion uint8) func() { MarkDrop: 0x10, MarkEndpoint: 0x11110000, }) - manager = newQoSPolicyManager(mangleTable, ruleRenderer, ipVersion) + // TODO (mazdak): add more tests for new nftables optimization + manager = newQoSPolicyManager(mangleTable, nil, ruleRenderer, ipVersion) }) It("should program QoS policy chain with no rule", func() { diff --git a/felix/generictables/actions.go b/felix/generictables/actions.go index e824ef9ff3b..7a1a3de76b5 100644 --- a/felix/generictables/actions.go +++ b/felix/generictables/actions.go @@ -35,7 +35,7 @@ type ActionFactory interface { Nflog(group uint16, prefix string, size int) Action LimitPacketRate(rate int64, burst int64, mark uint32) Action LimitNumConnections(num int64, rejectWith RejectWith) Action - DSCP(value string) Action + DSCP(value uint8) Action } type RejectWith string diff --git a/felix/iptables/actions.go b/felix/iptables/actions.go index 71b0bea1676..55fa73adf46 100644 --- a/felix/iptables/actions.go +++ b/felix/iptables/actions.go @@ -121,7 +121,7 @@ func (a *actionFactory) LimitNumConnections(num int64, rejectWith generictables. } } -func (a *actionFactory) DSCP(value string) generictables.Action { +func (a *actionFactory) DSCP(value uint8) generictables.Action { return DSCPAction{ Value: value, } @@ -479,13 +479,13 @@ func (a LimitNumConnectionsAction) String() string { } type DSCPAction struct { - Value string + Value uint8 } func (a DSCPAction) ToFragment(features *environment.Features) string { - return fmt.Sprintf("--jump DSCP --set-dscp %s", a.Value) + return fmt.Sprintf("--jump DSCP --set-dscp %d", a.Value) } func (a DSCPAction) String() string { - return fmt.Sprintf("DSCP %s", a.Value) + return fmt.Sprintf("DSCP %d", a.Value) } diff --git a/felix/nftables/actions.go b/felix/nftables/actions.go index 5f4e5026cde..7190a6679a2 100644 --- a/felix/nftables/actions.go +++ b/felix/nftables/actions.go @@ -134,7 +134,7 @@ func (a *actionSet) LimitNumConnections(num int64, rejectWith generictables.Reje } } -func (a *actionSet) DSCP(value string) generictables.Action { +func (a *actionSet) DSCP(value uint8) generictables.Action { return DSCPAction{ Value: value, } @@ -513,14 +513,12 @@ func (a LimitNumConnectionsAction) String() string { } type DSCPAction struct { - Value string + Value uint8 } func (a DSCPAction) ToFragment(features *environment.Features) string { - if a.Value == "vmap" { - return "ip dscp" - } - return fmt.Sprintf(" dscp set %d", a.Value) + return "ip dscp" + //return fmt.Sprintf(" dscp set %d", a.Value) } func (a DSCPAction) String() string { diff --git a/felix/rules/qos.go b/felix/rules/qos.go index ed89e5697c5..f88e3f7a4d0 100644 --- a/felix/rules/qos.go +++ b/felix/rules/qos.go @@ -15,8 +15,6 @@ package rules import ( - "strconv" - "github.com/projectcalico/calico/felix/generictables" ) @@ -54,7 +52,7 @@ func (r *DefaultRuleRenderer) defaultQoSPolicyRules(policies []QoSPolicy) *gener for _, p := range policies { rules = append(rules, generictables.Rule{ Match: r.NewMatch().SourceNet(p.SrcAddrs), - Action: r.DSCP(strconv.FormatUint(uint64(p.DSCP), 10)), + Action: r.DSCP(p.DSCP), }) } From d5a368c3af47a328736fded567bf984f9903b3a3 Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Thu, 21 Aug 2025 13:25:24 -0700 Subject: [PATCH 14/15] fix --- felix/fv/qos_policy_test.go | 4 ++-- felix/nftables/maps.go | 4 ++++ felix/nftables/match_builder.go | 1 + felix/rules/rule_defs.go | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/felix/fv/qos_policy_test.go b/felix/fv/qos_policy_test.go index 382669081d6..a395ae1233e 100644 --- a/felix/fv/qos_policy_test.go +++ b/felix/fv/qos_policy_test.go @@ -35,7 +35,7 @@ import ( api "github.com/projectcalico/calico/libcalico-go/lib/apis/v3" ) -var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apiconfig.DatastoreType{apiconfig.EtcdV3, apiconfig.Kubernetes}, func(getInfra infrastructure.InfraFactory) { +var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apiconfig.DatastoreType{apiconfig.Kubernetes}, func(getInfra infrastructure.InfraFactory) { const ( wepPortStr = "8055" ) @@ -170,7 +170,7 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ qos policy tests", []apicon }) It("pepper1 applying DSCP annotation should result is adding correct rules", func() { - time.Sleep(time.Minute * 20) + //time.Sleep(time.Minute * 20) dscp0 := numorstring.DSCPFromInt(0) // 0x0 dscp20 := numorstring.DSCPFromInt(20) // 0x14 dscp32 := numorstring.DSCPFromInt(32) // 0x20 diff --git a/felix/nftables/maps.go b/felix/nftables/maps.go index 257df6588a8..edfd2c56c9c 100644 --- a/felix/nftables/maps.go +++ b/felix/nftables/maps.go @@ -695,9 +695,13 @@ func mapType(t MapType, ipVersion int) string { return "ifname : verdict" case MapTypeSourceNetMatch: if ipVersion == 4 { + //return "ipv4_addr : integer" + //return "ipv4_addr : dscp_class" return "ipv4_addr : dscp" //return "ipv4_addr : verdict" } else { + //return "ipv6_addr : integer" + //return "ipv6_addr : dscp_class" return "ipv6_addr : dscp" //return "ipv6_addr : verdict" } diff --git a/felix/nftables/match_builder.go b/felix/nftables/match_builder.go index cd2516279ec..4250b2cba58 100644 --- a/felix/nftables/match_builder.go +++ b/felix/nftables/match_builder.go @@ -546,6 +546,7 @@ func (m nftMatch) OutInterfaceVMAP(name string) generictables.MatchCriteria { func (m nftMatch) SourceNetVMAP(name string) generictables.MatchCriteria { //return fmt.Sprintf(" dscp set %d", a.Value) + //m.clauses = append(m.clauses, fmt.Sprintf(" dscp set @-%s[ip saddr]", LegalizeSetName(name))) m.clauses = append(m.clauses, fmt.Sprintf(" dscp set ip saddr map @-%s", LegalizeSetName(name))) return m } diff --git a/felix/rules/rule_defs.go b/felix/rules/rule_defs.go index 5088859750d..401d7d81dd1 100644 --- a/felix/rules/rule_defs.go +++ b/felix/rules/rule_defs.go @@ -62,7 +62,7 @@ const ( ChainManglePostrouting = ChainNamePrefix + "POSTROUTING" ChainQoSPolicy = ChainNamePrefix + "qos-policy" - NftablesQoSPolicyMap = ChainNamePrefix + "qos-policy" + NftablesQoSPolicyMap = ChainNamePrefix + "qos-policy-map" IPSetIDAllPools = "all-ipam-pools" IPSetIDNATOutgoingMasqPools = "masq-ipam-pools" From add69cc45e3223ca027c44fb6a196dae10581d3e Mon Sep 17 00:00:00 2001 From: Mazdak Nasab Date: Fri, 22 Aug 2025 17:06:36 -0700 Subject: [PATCH 15/15] update --- felix/dataplane/linux/dscp_mgr.go | 8 ++++++-- felix/dataplane/linux/dscp_mgr_test.go | 6 +----- felix/fv/dscp_test.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/felix/dataplane/linux/dscp_mgr.go b/felix/dataplane/linux/dscp_mgr.go index ed8f7df2ea9..88b2dd7a766 100644 --- a/felix/dataplane/linux/dscp_mgr.go +++ b/felix/dataplane/linux/dscp_mgr.go @@ -156,8 +156,10 @@ func (m *dscpManager) CompleteDeferredWork() error { return dscpRules[i].SrcAddrs < dscpRules[j].SrcAddrs }) + logrus.Infof("marva0 %v", dscpRules) if m.mangleMaps != nil { - mappings := nftablesVMappings(dscpRules) + mappings := nftablesMappings(dscpRules) + logrus.Infof("marva %v", mappings) mapMeta := nftables.MapMetadata{Name: rules.NftablesQoSPolicyMap, Type: nftables.MapTypeSourceNetMatch} m.mangleMaps.AddOrReplaceMap(mapMeta, mappings) } @@ -170,10 +172,12 @@ func (m *dscpManager) CompleteDeferredWork() error { return nil } -func nftablesVMappings(rules []rules.DSCPRule) map[string][]string { +func nftablesMappings(rules []rules.DSCPRule) map[string][]string { mappings := map[string][]string{} + logrus.Infof("marva1 %v", rules) for _, r := range rules { mappings[r.SrcAddrs] = []string{fmt.Sprintf("%d", r.Value)} } + logrus.Infof("marva2 %v", mappings) return mappings } diff --git a/felix/dataplane/linux/dscp_mgr_test.go b/felix/dataplane/linux/dscp_mgr_test.go index a39d29cb31d..e2b91c7bbf9 100644 --- a/felix/dataplane/linux/dscp_mgr_test.go +++ b/felix/dataplane/linux/dscp_mgr_test.go @@ -45,12 +45,8 @@ func dscpManagerTests(ipVersion uint8) func() { MarkDrop: 0x10, MarkEndpoint: 0x11110000, }) -<<<<<<< HEAD:felix/dataplane/linux/qos_policy_mgr_test.go // TODO (mazdak): add more tests for new nftables optimization - manager = newQoSPolicyManager(mangleTable, nil, ruleRenderer, ipVersion) -======= - manager = newDSCPManager(mangleTable, ruleRenderer, ipVersion) ->>>>>>> open-source/master:felix/dataplane/linux/dscp_mgr_test.go + manager = newDSCPManager(mangleTable, nil, ruleRenderer, ipVersion) }) It("should program DSCP chain with no rule", func() { diff --git a/felix/fv/dscp_test.go b/felix/fv/dscp_test.go index 1d7159d7e21..a1a5d3719b0 100644 --- a/felix/fv/dscp_test.go +++ b/felix/fv/dscp_test.go @@ -177,7 +177,6 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ dscp tests", []apiconfig.Da }) It("pepper1 applying DSCP annotation should result is adding correct rules", func() { - //time.Sleep(time.Minute * 20) dscp0 := numorstring.DSCPFromInt(0) // 0x0 dscp20 := numorstring.DSCPFromInt(20) // 0x14 dscp32 := numorstring.DSCPFromInt(32) // 0x20 @@ -244,6 +243,7 @@ var _ = infrastructure.DatastoreDescribe("_BPF-SAFE_ dscp tests", []apiconfig.Da } ep2_2.UpdateInInfra(infra) + //time.Sleep(time.Minute * 20) cc.ResetExpectations() cc.ExpectSome(extClient, hostw) cc.ExpectSome(extClient, ep1_1)