From 69c72a3a0c0626bf592944e929ffaaed7dcde8d6 Mon Sep 17 00:00:00 2001 From: Yann Ramin Date: Thu, 25 Jan 2018 22:03:51 -0800 Subject: [PATCH] Add routes to all peered VPCs (config option) If the key `routeToVpcPeers` is set to `true` on the IPAM configuration, all known peered VPC CIDRs will be added to the IPvlan route table allowing for direct VPC<->VPC communication. Fixes #21 / #23 --- aws/vpc.go | 51 +++++++++++++++++++++++++++++++++++++++++++++ plugin/ipam/main.go | 10 +++++++++ 2 files changed, 61 insertions(+) diff --git a/aws/vpc.go b/aws/vpc.go index 13c2337..1b4aab5 100644 --- a/aws/vpc.go +++ b/aws/vpc.go @@ -14,6 +14,7 @@ import ( // VPCClient provides a view into a VPC type VPCClient interface { DescribeVPCCIDRs(vpcID string) ([]*net.IPNet, error) + DescribeVPCPeerCIDRs(vpcID string) ([]*net.IPNet, error) } type vpcCacheClient struct { @@ -35,6 +36,21 @@ func (v *vpcCacheClient) DescribeVPCCIDRs(vpcID string) (cidrs []*net.IPNet, err return } +func (v *vpcCacheClient) DescribeVPCPeerCIDRs(vpcID string) (cidrs []*net.IPNet, err error) { + key := fmt.Sprintf("vpc-peers-%v", vpcID) + state := cache.Get(key, &cidrs) + if state == cache.CacheFound { + return + } + cidrs, err = v.vpc.DescribeVPCPeerCIDRs(vpcID) + if err != nil { + return nil, err + } + cache.Store(key, v.expiration, &cidrs) + return + +} + type vpcclient struct { aws *awsclient } @@ -66,3 +82,38 @@ func (v *vpcclient) DescribeVPCCIDRs(vpcID string) ([]*net.IPNet, error) { } return cidrs, nil } + +// DescribeVPCPeerCIDRs returns a list of CIDRs for all peered VPCs to the given VPC +func (v *vpcclient) DescribeVPCPeerCIDRs(vpcID string) ([]*net.IPNet, error) { + ec2c, err := v.aws.newEC2() + if err != nil { + return nil, err + } + + req := &ec2.DescribeVpcPeeringConnectionsInput{} + + res, err := ec2c.DescribeVpcPeeringConnections(req) + if err != nil { + return nil, err + } + + var cidrs []*net.IPNet + + for _, peering := range res.VpcPeeringConnections { + var peer *ec2.VpcPeeringConnectionVpcInfo + + if vpcID == *peering.AccepterVpcInfo.VpcId { + peer = peering.RequesterVpcInfo + } else if vpcID == *peering.RequesterVpcInfo.VpcId { + peer = peering.AccepterVpcInfo + } + + for _, cidrBlock := range peer.CidrBlockSet { + _, cidr, err := net.ParseCIDR(*cidrBlock.CidrBlock) + if err == nil { + cidrs = append(cidrs, cidr) + } + } + } + return cidrs, nil +} diff --git a/plugin/ipam/main.go b/plugin/ipam/main.go index 1f6f87b..6fcb900 100644 --- a/plugin/ipam/main.go +++ b/plugin/ipam/main.go @@ -48,6 +48,7 @@ type IPAMConfig struct { SubnetTags map[string]string `json:"subnetTags"` IfaceIndex int `json:"interfaceIndex"` SkipDeallocation bool `json:"skipDeallocation"` + RouteToVPCPeers bool `json:"routeToVpcPeers"` } func init() { @@ -156,6 +157,15 @@ func cmdAdd(args *skel.CmdArgs) error { return fmt.Errorf("Unable to enumerate CIDRs from the AWS API due to a specific meta-data bug %v", err) } } + + if conf.IPAM.RouteToVPCPeers { + peerCidr, err := aws.DefaultClient.DescribeVPCPeerCIDRs(alloc.Interface.VpcID) + if err != nil { + return fmt.Errorf("unable to enumerate peer CIDrs %v", err) + } + cidrs = append(cidrs, peerCidr...) + } + // add routes for all VPC cidrs via the subnet gateway for _, dst := range cidrs { result.Routes = append(result.Routes, &types.Route{*dst, gw})