From 9ef473f547b83dcd071b0ec01a0759cdfcf9faa1 Mon Sep 17 00:00:00 2001 From: Sergei Lukianov Date: Thu, 14 Dec 2023 02:18:09 -0800 Subject: [PATCH] [agent] drop traffic to own ipns subnets on external conn --- api/agent/v1alpha2/agent_types.go | 1 + api/agent/v1alpha2/zz_generated.deepcopy.go | 7 +++ .../bases/agent.githedgehog.com_agents.yaml | 12 ++++ docs/api.md | 2 + pkg/agent/dozer/bcm/plan.go | 29 ++++++++++ pkg/agent/dozer/bcm/spec_acl.go | 57 ++++++++++++++----- pkg/agent/dozer/dozer.go | 1 + pkg/ctrl/agent/agent_ctrl.go | 12 ++++ 8 files changed, 108 insertions(+), 13 deletions(-) diff --git a/api/agent/v1alpha2/agent_types.go b/api/agent/v1alpha2/agent_types.go index 732b81bc..93612a14 100644 --- a/api/agent/v1alpha2/agent_types.go +++ b/api/agent/v1alpha2/agent_types.go @@ -41,6 +41,7 @@ type AgentSpec struct { VPCPeerings map[string]vpcapi.VPCPeeringSpec `json:"vpcPeers,omitempty"` VPCLoopbackLinks map[string]string `json:"vpcLoopbackLinks,omitempty"` VPCLoopbackVLANs map[string]uint16 `json:"vpcLoopbackVLANs,omitempty"` + IPv4Namespaces map[string]vpcapi.IPv4NamespaceSpec `json:"ipv4Namespaces,omitempty"` Externals map[string]vpcapi.ExternalSpec `json:"externals,omitempty"` ExternalAttachments map[string]vpcapi.ExternalAttachmentSpec `json:"externalAttachments,omitempty"` ExternalPeerings map[string]vpcapi.ExternalPeeringSpec `json:"externalPeerings,omitempty"` diff --git a/api/agent/v1alpha2/zz_generated.deepcopy.go b/api/agent/v1alpha2/zz_generated.deepcopy.go index 00039f7c..fb3ca5df 100644 --- a/api/agent/v1alpha2/zz_generated.deepcopy.go +++ b/api/agent/v1alpha2/zz_generated.deepcopy.go @@ -149,6 +149,13 @@ func (in *AgentSpec) DeepCopyInto(out *AgentSpec) { (*out)[key] = val } } + if in.IPv4Namespaces != nil { + in, out := &in.IPv4Namespaces, &out.IPv4Namespaces + *out = make(map[string]vpcv1alpha2.IPv4NamespaceSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } if in.Externals != nil { in, out := &in.Externals, &out.Externals *out = make(map[string]vpcv1alpha2.ExternalSpec, len(*in)) diff --git a/config/crd/bases/agent.githedgehog.com_agents.yaml b/config/crd/bases/agent.githedgehog.com_agents.yaml index 94ec5249..bee00a21 100644 --- a/config/crd/bases/agent.githedgehog.com_agents.yaml +++ b/config/crd/bases/agent.githedgehog.com_agents.yaml @@ -393,6 +393,18 @@ spec: type: string type: object type: object + ipv4Namespaces: + additionalProperties: + description: IPv4NamespaceSpec defines the desired state of IPv4Namespace + properties: + subnets: + items: + type: string + maxItems: 10 + minItems: 1 + type: array + type: object + type: object irbVLANs: additionalProperties: type: integer diff --git a/docs/api.md b/docs/api.md index dca1da51..09072aa1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -58,6 +58,7 @@ _Appears in:_ | `vpcPeers` _object (keys:string, values:[VPCPeeringSpec](#vpcpeeringspec))_ | | | `vpcLoopbackLinks` _object (keys:string, values:string)_ | | | `vpcLoopbackVLANs` _object (keys:string, values:integer)_ | | +| `ipv4Namespaces` _object (keys:string, values:[IPv4NamespaceSpec](#ipv4namespacespec))_ | | | `externals` _object (keys:string, values:[ExternalSpec](#externalspec))_ | | | `externalAttachments` _object (keys:string, values:[ExternalAttachmentSpec](#externalattachmentspec))_ | | | `externalPeerings` _object (keys:string, values:[ExternalPeeringSpec](#externalpeeringspec))_ | | @@ -588,6 +589,7 @@ IPv4Namespace is the Schema for the ipv4namespaces API IPv4NamespaceSpec defines the desired state of IPv4Namespace _Appears in:_ +- [AgentSpec](#agentspec) - [IPv4Namespace](#ipv4namespace) | Field | Description | diff --git a/pkg/agent/dozer/bcm/plan.go b/pkg/agent/dozer/bcm/plan.go index afbdccbf..9513b497 100644 --- a/pkg/agent/dozer/bcm/plan.go +++ b/pkg/agent/dozer/bcm/plan.go @@ -516,6 +516,27 @@ func planExternals(agent *agentapi.Agent, spec *dozer.Spec) error { }, } + spec.ACLs[ipnsEgressAccessList(external.IPv4Namespace)] = &dozer.SpecACL{ + Entries: map[uint32]*dozer.SpecACLEntry{ + 65535: { + Action: dozer.SpecACLEntryActionAccept, + }, + }, + } + + ipns, exists := agent.Spec.IPv4Namespaces[external.IPv4Namespace] + if !exists { + return errors.Errorf("ipv4 namespace %s not found for external %s", external.IPv4Namespace, externalName) + } + seq := uint32(10) + for _, subnet := range ipns.Subnets { + spec.ACLs[ipnsEgressAccessList(external.IPv4Namespace)].Entries[seq] = &dozer.SpecACLEntry{ + DestinationAddress: stringPtr(subnet), + Action: dozer.SpecACLEntryActionDrop, + } + seq += 10 + } + if spec.VRFs[ipnsVrfName] == nil { protocolIP, _, err := net.ParseCIDR(agent.Spec.Switch.ProtocolIP) if err != nil { @@ -637,6 +658,10 @@ func planExternals(agent *agentapi.Agent, spec *dozer.Spec) error { IPv4UnicastImportPolicies: []string{inboundRouteMapName(attach.External)}, IPv4UnicastExportPolicies: []string{outboundRouteMapName(attach.External)}, } + + spec.ACLInterfaces[subIfaceName] = &dozer.SpecACLInterface{ + Egress: stringPtr(ipnsEgressAccessList(ipns)), + } } return nil @@ -1453,6 +1478,10 @@ func importVrfRouteMapName(vpc string) string { return fmt.Sprintf("import-vrf--%s", vpc) } +func ipnsEgressAccessList(ipns string) string { + return fmt.Sprintf("ipns-egress--%s", ipns) +} + func stringPtr(s string) *string { return &s } func uint8Ptr(u uint8) *uint8 { return &u } diff --git a/pkg/agent/dozer/bcm/spec_acl.go b/pkg/agent/dozer/bcm/spec_acl.go index 1592ba06..b788adcd 100644 --- a/pkg/agent/dozer/bcm/spec_acl.go +++ b/pkg/agent/dozer/bcm/spec_acl.go @@ -147,20 +147,40 @@ var specACLInterfaceEnforcer = &DefaultValueEnforcer[string, *dozer.SpecACLInter UpdateWeight: ActionWeightACLInterfaceUpdate, DeleteWeight: ActionWeightACLInterfaceDelete, Marshal: func(name string, value *dozer.SpecACLInterface) (ygot.ValidatedGoStruct, error) { - aclSets := &oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets{ - IngressAclSet: map[oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet_Key]*oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet{}, + var ingressAclSets *oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets + if value.Ingress != nil { + ingressAclSets = &oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets{ + IngressAclSet: map[oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet_Key]*oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet{ + { + SetName: *value.Ingress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + }: { + SetName: value.Ingress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + Config: &oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet_Config{ + SetName: value.Ingress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + }, + }, + }, + } } - if value.Ingress != nil { - aclSets.IngressAclSet[oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet_Key{ - SetName: *value.Ingress, - Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, - }] = &oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet{ - SetName: value.Ingress, - Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, - Config: &oc.OpenconfigAcl_Acl_Interfaces_Interface_IngressAclSets_IngressAclSet_Config{ - SetName: value.Ingress, - Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + var egressAclSets *oc.OpenconfigAcl_Acl_Interfaces_Interface_EgressAclSets + if value.Egress != nil { + egressAclSets = &oc.OpenconfigAcl_Acl_Interfaces_Interface_EgressAclSets{ + EgressAclSet: map[oc.OpenconfigAcl_Acl_Interfaces_Interface_EgressAclSets_EgressAclSet_Key]*oc.OpenconfigAcl_Acl_Interfaces_Interface_EgressAclSets_EgressAclSet{ + { + SetName: *value.Egress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + }: { + SetName: value.Egress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + Config: &oc.OpenconfigAcl_Acl_Interfaces_Interface_EgressAclSets_EgressAclSet_Config{ + SetName: value.Egress, + Type: oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4, + }, + }, }, } } @@ -177,7 +197,8 @@ var specACLInterfaceEnforcer = &DefaultValueEnforcer[string, *dozer.SpecACLInter Interface: ygot.String(name), }, }, - IngressAclSets: aclSets, + IngressAclSets: ingressAclSets, + EgressAclSets: egressAclSets, }, }, }, nil @@ -302,6 +323,7 @@ func unmarshalOCACLInterfaces(ocVal *oc.OpenconfigAcl_Acl) (map[string]*dozer.Sp } var ingress *string + var egress *string for key, value := range iface.IngressAclSets.IngressAclSet { if key.Type != oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4 { @@ -311,8 +333,17 @@ func unmarshalOCACLInterfaces(ocVal *oc.OpenconfigAcl_Acl) (map[string]*dozer.Sp ingress = value.SetName } + for key, value := range iface.EgressAclSets.EgressAclSet { + if key.Type != oc.OpenconfigAcl_ACL_TYPE_ACL_IPV4 { + continue + } + + egress = value.SetName + } + interfaces[name] = &dozer.SpecACLInterface{ Ingress: ingress, + Egress: egress, } } diff --git a/pkg/agent/dozer/dozer.go b/pkg/agent/dozer/dozer.go index dd48a487..ede2513e 100644 --- a/pkg/agent/dozer/dozer.go +++ b/pkg/agent/dozer/dozer.go @@ -316,6 +316,7 @@ const ( type SpecACLInterface struct { Ingress *string `json:"ingress,omitempty"` + Egress *string `json:"egress,omitempty"` } type SpecVXLANTunnel struct { diff --git a/pkg/ctrl/agent/agent_ctrl.go b/pkg/ctrl/agent/agent_ctrl.go index bde80a54..3415ca5d 100644 --- a/pkg/ctrl/agent/agent_ctrl.go +++ b/pkg/ctrl/agent/agent_ctrl.go @@ -412,6 +412,17 @@ func (r *AgentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl } } + ipv4NamespaceList := &vpcapi.IPv4NamespaceList{} + err = r.List(ctx, ipv4NamespaceList, client.InNamespace(sw.Namespace)) + if err != nil { + return ctrl.Result{}, errors.Wrapf(err, "error listing ipv4 namespaces") + } + + ipv4Namespaces := map[string]vpcapi.IPv4NamespaceSpec{} + for _, ns := range ipv4NamespaceList.Items { + ipv4Namespaces[ns.Name] = ns.Spec + } + agent := &agentapi.Agent{ObjectMeta: switchNsName} _, err = ctrlutil.CreateOrUpdate(ctx, r.Client, agent, func() error { agent.Labels = sw.Labels @@ -424,6 +435,7 @@ func (r *AgentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl agent.Spec.VPCs = vpcs agent.Spec.VPCAttachments = attaches agent.Spec.VPCPeerings = peers + agent.Spec.IPv4Namespaces = ipv4Namespaces agent.Spec.Externals = externals agent.Spec.ExternalAttachments = externalAttaches agent.Spec.ExternalPeerings = externalPeerings