diff --git a/mocks/amazon-vcp-resource-controller-k8s/pkg/aws/ec2/mock_instance.go b/mocks/amazon-vcp-resource-controller-k8s/pkg/aws/ec2/mock_instance.go index 902cafb1..d287cff4 100644 --- a/mocks/amazon-vcp-resource-controller-k8s/pkg/aws/ec2/mock_instance.go +++ b/mocks/amazon-vcp-resource-controller-k8s/pkg/aws/ec2/mock_instance.go @@ -212,6 +212,34 @@ func (mr *MockEC2InstanceMockRecorder) SubnetMask() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubnetMask", reflect.TypeOf((*MockEC2Instance)(nil).SubnetMask)) } +// SubnetV6CidrBlock mocks base method. +func (m *MockEC2Instance) SubnetV6CidrBlock() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubnetV6CidrBlock") + ret0, _ := ret[0].(string) + return ret0 +} + +// SubnetV6CidrBlock indicates an expected call of SubnetV6CidrBlock. +func (mr *MockEC2InstanceMockRecorder) SubnetV6CidrBlock() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubnetV6CidrBlock", reflect.TypeOf((*MockEC2Instance)(nil).SubnetV6CidrBlock)) +} + +// SubnetV6Mask mocks base method. +func (m *MockEC2Instance) SubnetV6Mask() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubnetV6Mask") + ret0, _ := ret[0].(string) + return ret0 +} + +// SubnetV6Mask indicates an expected call of SubnetV6Mask. +func (mr *MockEC2InstanceMockRecorder) SubnetV6Mask() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubnetV6Mask", reflect.TypeOf((*MockEC2Instance)(nil).SubnetV6Mask)) +} + // Type mocks base method. func (m *MockEC2Instance) Type() string { m.ctrl.T.Helper() diff --git a/pkg/aws/ec2/instance.go b/pkg/aws/ec2/instance.go index 698943ae..adde9058 100644 --- a/pkg/aws/ec2/instance.go +++ b/pkg/aws/ec2/instance.go @@ -38,15 +38,18 @@ type ec2Instance struct { // subnetId is the instance's subnet id instanceSubnetID string // instanceSubnetCidrBlock is the cidr block of the instance's subnet - instanceSubnetCidrBlock string + instanceSubnetCidrBlock string + instanceSubnetV6CidrBlock string // currentSubnetID can either point to the Subnet ID of the instance or subnet ID from the ENIConfig currentSubnetID string // currentSubnetCIDRBlock can either point to the Subnet CIDR block for instance subnet or subnet from ENIConfig - currentSubnetCIDRBlock string + currentSubnetCIDRBlock string + currentSubnetV6CIDRBlock string // currentInstanceSecurityGroups can either point to the primary network interface security groups or the security groups in ENIConfig currentInstanceSecurityGroups []string // subnetMask is the mask of the subnet CIDR block - subnetMask string + subnetMask string + subnetV6Mask string // deviceIndexes is the list of indexes used by the EC2 Instance deviceIndexes []bool // primaryENIGroups is the security group used by the primary network interface @@ -70,7 +73,9 @@ type EC2Instance interface { InstanceID() string SubnetID() string SubnetMask() string + SubnetV6Mask() string SubnetCidrBlock() string + SubnetV6CidrBlock() string PrimaryNetworkInterfaceID() string CurrentInstanceSecurityGroups() []string SetNewCustomNetworkingSpec(subnetID string, securityGroup []string) @@ -110,8 +115,16 @@ func (i *ec2Instance) LoadDetails(ec2APIHelper api.EC2APIHelper) error { i.instanceSubnetID, i.instanceID) } i.instanceSubnetCidrBlock = *instanceSubnet.CidrBlock - i.subnetMask = strings.Split(i.instanceSubnetCidrBlock, "/")[1] + // Cache IPv6 CIDR block if one is present + for _, v6CidrBlock := range instanceSubnet.Ipv6CidrBlockAssociationSet { + if v6CidrBlock.Ipv6CidrBlock != nil { + i.instanceSubnetV6CidrBlock = *v6CidrBlock.Ipv6CidrBlock + i.subnetV6Mask = strings.Split(i.instanceSubnetV6CidrBlock, "/")[1] + break + } + } + i.instanceType = *instance.InstanceType limits, ok := vpc.Limits[i.instanceType] if !ok { @@ -178,6 +191,13 @@ func (i *ec2Instance) SubnetCidrBlock() string { return i.currentSubnetCIDRBlock } +func (i *ec2Instance) SubnetV6CidrBlock() string { + i.lock.RLock() + defer i.lock.RUnlock() + + return i.currentSubnetV6CIDRBlock +} + // Name returns the name of the node func (i *ec2Instance) Name() string { return i.name @@ -231,6 +251,13 @@ func (i *ec2Instance) SubnetMask() string { return i.subnetMask } +func (i *ec2Instance) SubnetV6Mask() string { + i.lock.Lock() + defer i.lock.Unlock() + + return i.subnetV6Mask +} + // SetNewCustomNetworkingSpec updates the subnet ID and subnet CIDR block for the instance func (i *ec2Instance) SetNewCustomNetworkingSpec(subnet string, securityGroups []string) { i.lock.Lock() @@ -271,12 +298,14 @@ func (i *ec2Instance) updateCurrentSubnetAndCidrBlock(ec2APIHelper api.EC2APIHel } i.currentSubnetID = i.newCustomNetworkingSubnetID i.currentSubnetCIDRBlock = *customSubnet.CidrBlock + // NOTE: IPv6 does not support custom networking } } else { // Custom networking in not being used, point to the primary network interface security group and // subnet details i.currentSubnetID = i.instanceSubnetID i.currentSubnetCIDRBlock = i.instanceSubnetCidrBlock + i.currentSubnetV6CIDRBlock = i.instanceSubnetV6CidrBlock i.currentInstanceSecurityGroups = i.primaryENISecurityGroups } diff --git a/pkg/provider/branch/trunk/trunk.go b/pkg/provider/branch/trunk/trunk.go index 06465d60..fb408f8e 100644 --- a/pkg/provider/branch/trunk/trunk.go +++ b/pkg/provider/branch/trunk/trunk.go @@ -111,12 +111,14 @@ type ENIDetails struct { ID string `json:"eniId"` // MacAdd is the MAC address of the network interface MACAdd string `json:"ifAddress"` - // BranchIp is the primary IP of the branch Network interface + // IPv4 and/or IPv6 address assigned to the branch Network interface IPV4Addr string `json:"privateIp"` + IPV6Addr string `json:"ipv6Addr"` // VlanId is the VlanId of the branch network interface VlanID int `json:"vlanId"` // SubnetCIDR is the CIDR block of the subnet - SubnetCIDR string `json:"subnetCidr"` + SubnetCIDR string `json:"subnetCidr"` + SubnetV6CIDR string `json:"subnetV6Cidr"` // deletionTimeStamp is the time when the pod was marked deleted. deletionTimeStamp time.Time // deleteRetryCount is the @@ -358,9 +360,17 @@ func (t *trunkENI) CreateAndAssociateBranchENIs(pod *v1.Pod, securityGroups []st break } + // Branch ENI can have an IPv4 address, IPv6 address, or both + var v4Addr, v6Addr string + if nwInterface.PrivateIpAddress != nil { + v4Addr = *nwInterface.PrivateIpAddress + } + if nwInterface.Ipv6Address != nil { + v6Addr = *nwInterface.Ipv6Address + } newENI := &ENIDetails{ID: *nwInterface.NetworkInterfaceId, MACAdd: *nwInterface.MacAddress, - IPV4Addr: *nwInterface.PrivateIpAddress, SubnetCIDR: t.instance.SubnetCidrBlock(), VlanID: vlanID} - + IPV4Addr: v4Addr, IPV6Addr: v6Addr, SubnetCIDR: t.instance.SubnetCidrBlock(), + SubnetV6CIDR: t.instance.SubnetV6CidrBlock(), VlanID: vlanID} newENIs = append(newENIs, newENI) // Associate Branch to trunk @@ -521,9 +531,10 @@ func (t *trunkENI) GetBranchInterfacesFromEC2() (eniDetails []*ENIDetails, err e // For each association build the map of branch ENIs with the interface id and the vlan id for _, association := range associations { eniDetail := &ENIDetails{ - ID: *association.BranchInterfaceId, - VlanID: int(*association.VlanId), - SubnetCIDR: t.instance.SubnetCidrBlock(), + ID: *association.BranchInterfaceId, + VlanID: int(*association.VlanId), + SubnetCIDR: t.instance.SubnetCidrBlock(), + SubnetV6CIDR: t.instance.SubnetV6CidrBlock(), } eniDetails = append(eniDetails, eniDetail) } diff --git a/pkg/provider/branch/trunk/trunk_test.go b/pkg/provider/branch/trunk/trunk_test.go index 4c41b3c6..f1bc1168 100644 --- a/pkg/provider/branch/trunk/trunk_test.go +++ b/pkg/provider/branch/trunk/trunk_test.go @@ -40,6 +40,7 @@ var ( InstanceType = "c5.xlarge" SubnetId = "subnet-00000000000000000" SubnetCidrBlock = "192.168.0.0/16" + SubnetV6CidrBlock = "2600::/64" NodeName = "test-node" FakeInstance = ec2.NewEC2Instance(NodeName, InstanceId, config.OSLinux) InstanceSecurityGroup = []string{"sg-1", "sg-2"} @@ -56,9 +57,9 @@ var ( UID: MockPodUID1, Name: MockPodName1, Namespace: MockPodNamespace1, - Annotations: map[string]string{config.ResourceNamePodENI: "[{\"eniId\":\"eni-00000000000000000\",\"ifAddress\":\"FF:FF:FF:FF:FF:FF\",\"privateIp\":\"192.168.0.15\"" + - ",\"vlanId\":1,\"subnetCidr\":\"192.168.0.0/16\"},{\"eniId\":\"eni-00000000000000001\",\"ifAddress\":\"" + - "FF:FF:FF:FF:FF:F9\",\"privateIp\":\"192.168.0.16\",\"vlanId\":2,\"subnetCidr\":\"192.168.0.0/16\"}]"}}, + Annotations: map[string]string{config.ResourceNamePodENI: "[{\"eniId\":\"eni-00000000000000000\",\"ifAddress\":\"FF:FF:FF:FF:FF:FF\",\"privateIp\":\"192.168.0.15\"," + + "\"ipv6Addr\":\"2600::\",\"vlanId\":1,\"subnetCidr\":\"192.168.0.0/16\",\"subnetV6Cidr\":\"2600::/64\"},{\"eniId\":\"eni-00000000000000001\",\"ifAddress\":\"" + + "FF:FF:FF:FF:FF:F9\",\"privateIp\":\"192.168.0.16\",\"ipv6Addr\":\"2600::1\",\"vlanId\":2,\"subnetCidr\":\"192.168.0.0/16\",\"subnetV6Cidr\":\"2600::/64\"}]"}}, Spec: v1.PodSpec{NodeName: NodeName}, Status: v1.PodStatus{}, } @@ -88,17 +89,20 @@ var ( SecurityGroups = []string{SecurityGroup1, SecurityGroup2} // Branch Interface 1 - Branch1Id = "eni-00000000000000000" - MacAddr1 = "FF:FF:FF:FF:FF:FF" - BranchIp1 = "192.168.0.15" - VlanId1 = 1 + Branch1Id = "eni-00000000000000000" + MacAddr1 = "FF:FF:FF:FF:FF:FF" + BranchIp1 = "192.168.0.15" + BranchV6Ip1 = "2600::" + VlanId1 = 1 EniDetails1 = &ENIDetails{ - ID: Branch1Id, - MACAdd: MacAddr1, - IPV4Addr: BranchIp1, - VlanID: VlanId1, - SubnetCIDR: SubnetCidrBlock, + ID: Branch1Id, + MACAdd: MacAddr1, + IPV4Addr: BranchIp1, + IPV6Addr: BranchV6Ip1, + VlanID: VlanId1, + SubnetCIDR: SubnetCidrBlock, + SubnetV6CIDR: SubnetV6CidrBlock, } branchENIs1 = []*ENIDetails{EniDetails1} @@ -107,26 +111,31 @@ var ( MacAddress: &MacAddr1, NetworkInterfaceId: &Branch1Id, PrivateIpAddress: &BranchIp1, + Ipv6Address: &BranchV6Ip1, } // Branch Interface 2 - Branch2Id = "eni-00000000000000001" - MacAddr2 = "FF:FF:FF:FF:FF:F9" - BranchIp2 = "192.168.0.16" - VlanId2 = 2 + Branch2Id = "eni-00000000000000001" + MacAddr2 = "FF:FF:FF:FF:FF:F9" + BranchIp2 = "192.168.0.16" + BranchV6Ip2 = "2600::1" + VlanId2 = 2 EniDetails2 = &ENIDetails{ - ID: Branch2Id, - MACAdd: MacAddr2, - IPV4Addr: BranchIp2, - VlanID: VlanId2, - SubnetCIDR: SubnetCidrBlock, + ID: Branch2Id, + MACAdd: MacAddr2, + IPV4Addr: BranchIp2, + IPV6Addr: BranchV6Ip2, + VlanID: VlanId2, + SubnetCIDR: SubnetCidrBlock, + SubnetV6CIDR: SubnetV6CidrBlock, } BranchInterface2 = &awsEc2.NetworkInterface{ MacAddress: &MacAddr2, NetworkInterfaceId: &Branch2Id, PrivateIpAddress: &BranchIp2, + Ipv6Address: &BranchV6Ip2, } branchENIs2 = []*ENIDetails{EniDetails2} @@ -361,6 +370,7 @@ func TestTrunkENI_GetBranchInterfacesFromEC2(t *testing.T) { ec2APIHelper.EXPECT().DescribeTrunkInterfaceAssociation(&trunkId).Return(trunkAssociationsBranch1And2, nil) mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(2) + mockInstance.EXPECT().SubnetV6CidrBlock().Return(SubnetV6CidrBlock).Times(2) eniDetails, err := trunkENI.GetBranchInterfacesFromEC2() @@ -778,6 +788,7 @@ func TestTrunkENI_CreateAndAssociateBranchENIs(t *testing.T) { mockInstance.EXPECT().Type().Return(InstanceType) mockInstance.EXPECT().SubnetID().Return(SubnetId).Times(2) mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(2) + mockInstance.EXPECT().SubnetV6CidrBlock().Return(SubnetV6CidrBlock).Times(2) mockEC2APIHelper.EXPECT().CreateNetworkInterface(&BranchEniDescription, &SubnetId, SecurityGroups, vlan1Tag, nil, nil).Return(BranchInterface1, nil) @@ -810,6 +821,7 @@ func TestTrunkENI_CreateAndAssociateBranchENIs_InstanceSecurityGroup(t *testing. mockInstance.EXPECT().Type().Return(InstanceType) mockInstance.EXPECT().SubnetID().Return(SubnetId).Times(2) mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(2) + mockInstance.EXPECT().SubnetV6CidrBlock().Return(SubnetV6CidrBlock).Times(2) mockInstance.EXPECT().CurrentInstanceSecurityGroups().Return(InstanceSecurityGroup) mockEC2APIHelper.EXPECT().CreateNetworkInterface(&BranchEniDescription, &SubnetId, InstanceSecurityGroup, @@ -843,6 +855,7 @@ func TestTrunkENI_CreateAndAssociateBranchENIs_ErrorAssociate(t *testing.T) { mockInstance.EXPECT().Type().Return(InstanceType) mockInstance.EXPECT().SubnetID().Return(SubnetId).Times(2) mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(2) + mockInstance.EXPECT().SubnetV6CidrBlock().Return(SubnetV6CidrBlock).Times(2) gomock.InOrder( mockEC2APIHelper.EXPECT().CreateNetworkInterface(&BranchEniDescription, &SubnetId, SecurityGroups, @@ -870,6 +883,7 @@ func TestTrunkENI_CreateAndAssociateBranchENIs_ErrorCreate(t *testing.T) { mockInstance.EXPECT().Type().Return(InstanceType) mockInstance.EXPECT().SubnetID().Return(SubnetId).Times(2) mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(1) + mockInstance.EXPECT().SubnetV6CidrBlock().Return(SubnetV6CidrBlock).Times(1) gomock.InOrder( mockEC2APIHelper.EXPECT().CreateNetworkInterface(&BranchEniDescription, &SubnetId, SecurityGroups, vlan1Tag, diff --git a/scripts/gen_mocks.sh b/scripts/gen_mocks.sh index 21dbc9c2..550c2215 100755 --- a/scripts/gen_mocks.sh +++ b/scripts/gen_mocks.sh @@ -21,7 +21,7 @@ mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/node/mock_n mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/utils/mock_k8shelper.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/utils SecurityGroupForPodsAPI # package pool mocks mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/pool/mock_pool.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/pool Pool -# package resource maocks +# package resource mocks mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/resource/mock_resources.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/resource ResourceManager -# package condition maocks +# package condition mocks mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/condition/mock_condition.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/condition Conditions