Skip to content

Commit

Permalink
feat: vpc peering connection
Browse files Browse the repository at this point in the history
  • Loading branch information
fanriming authored and oilbeater committed Feb 14, 2022
1 parent 9c5556c commit a34bb35
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 0 deletions.
13 changes: 13 additions & 0 deletions dist/images/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,15 @@ spec:
type: string
type: object
type: array
vpcPeerings:
items:
properties:
remoteVpc:
type: string
localConnectIP:
type: string
type: object
type: array
type: object
status:
properties:
Expand Down Expand Up @@ -351,6 +360,10 @@ spec:
items:
type: string
type: array
vpcPeerings:
items:
type: string
type: array
tcpLoadBalancer:
type: string
tcpSessionLoadBalancer:
Expand Down
Binary file added docs/vpc-peering-ovn.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions docs/vpc-peering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# VPC peering connection
## What is VPC peering?
A VPC peering connection is a networking connection between two VPCs that enables you to route traffic between them using private IPv4 addresses or IPv6 addresses. Instances in either VPC can communicate with each other as if they are within the same network.

![vpc-peering.png](vpc-peering.png)

## Corresponding OVN model

![vpc-peering-ovn.png](vpc-peering-ovn.png)

## Usage
1. Create two VPC with subnet
```yaml
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
name: vpc-1
spec: {}
---
kind: Subnet
apiVersion: kubeovn.io/v1
metadata:
name: net1
spec:
vpc: vpc-1
cidrBlock: 10.0.0.0/16
---
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
name: vpc-2
spec: {}
---
kind: Subnet
apiVersion: kubeovn.io/v1
metadata:
name: net2
spec:
vpc: vpc-2
cidrBlock: 172.31.0.0/16
```

2. Establish peer connection and configure static route between vpc-1 and vpc-2
```yaml
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
name: vpc-1
spec:
vpcPeerings:
- remoteVpc: vpc-2
localConnectIP: 169.254.0.1/30 # The interconnection address for local vpc
staticRoutes:
- cidr: 172.31.0.0/16 # CIDR of remote vpc subnet
nextHopIP: 169.254.0.2 # The interconnection address for remote vpc
policy: policyDst
---
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
name: vpc-1
spec:
vpcPeerings:
- remoteVpc: vpc-2
localConnectIP: 169.254.0.2/30 # The interconnection address for local vpc
staticRoutes:
- cidr: 10.0.0.0/16 # CIDR of remote vpc subnet
nextHopIP: 169.254.0.1 # The interconnection address for remote vpc
policy: policyDst
```
The subnets of the two VPCs can communicate with each other now.

## Limitation
1. To avoid routing problems, the subnet CIDR of two VPCs cannot overlap.
2. The interconnection address cannot overlap with the subnet CIDR.
3. You cannot establish multiple VPC peer connections between two VPCs at the same time.
4. Currently, only custom VPCs can use this feature.
Binary file added docs/vpc-peering.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions pkg/apis/kubeovn/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ type VpcSpec struct {
Namespaces []string `json:"namespaces,omitempty"`
StaticRoutes []*StaticRoute `json:"staticRoutes,omitempty"`
PolicyRoutes []*PolicyRoute `json:"policyRoutes,omitempty"`
VpcPeerings []*VpcPeering `json:"vpcPeerings,omitempty"`
}

type VpcPeering struct {
RemoteVpc string `json:"remoteVpc,omitempty"`
LocalConnectIP string `json:"localConnectIP,omitempty"`
}

type RoutePolicy string
Expand Down Expand Up @@ -379,6 +385,7 @@ type VpcStatus struct {
TcpSessionLoadBalancer string `json:"tcpSessionLoadBalancer"`
UdpSessionLoadBalancer string `json:"udpSessionLoadBalancer"`
Subnets []string `json:"subnets"`
VpcPeerings []string `json:"vpcPeerings"`
}

// Condition describes the state of an object at a certain point.
Expand Down
32 changes: 32 additions & 0 deletions pkg/apis/kubeovn/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions pkg/controller/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func (c *Controller) gc() error {
c.gcPortGroup,
c.gcStaticRoute,
c.gcVpcNatGateway,
c.gcLogicalRouterPort,
}
for _, gcFunc := range gcFunctions {
if err := gcFunc(); err != nil {
Expand All @@ -39,6 +40,36 @@ func (c *Controller) gc() error {
return nil
}

func (c *Controller) gcLogicalRouterPort() error {
klog.Infof("start to gc logical router port")
vpcs, err := c.vpcsLister.List(labels.Everything())
if err != nil {
klog.Errorf("failed to list vpc, %v", err)
return err
}

var exceptPeerPorts []string
for _, vpc := range vpcs {
for _, peer := range vpc.Status.VpcPeerings {
exceptPeerPorts = append(exceptPeerPorts, fmt.Sprintf("%s-%s", vpc.Name, peer))
}
}
lrps, err := c.ovnClient.ListLogicalEntity("logical_router_port", "peer!=[]")
if err != nil {
klog.Errorf("failed to list logical router port, %v", err)
return err
}
for _, lrp := range lrps {
if !util.ContainsString(exceptPeerPorts, lrp) {
if err = c.ovnClient.DeleteLogicalRouterPort(lrp); err != nil {
klog.Errorf("failed to delete logical router port %s, %v", lrp, err)
return err
}
}
}
return nil
}

func (c *Controller) gcVpcNatGateway() error {
klog.Infof("start to gc vpc nat gateway")
gws, err := c.vpcNatGatewayLister.List(labels.Everything())
Expand Down
24 changes: 24 additions & 0 deletions pkg/controller/vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ func (c *Controller) enqueueUpdateVpc(old, new interface{}) {
if !newVpc.DeletionTimestamp.IsZero() ||
!reflect.DeepEqual(oldVpc.Spec.Namespaces, newVpc.Spec.Namespaces) ||
!reflect.DeepEqual(oldVpc.Spec.StaticRoutes, newVpc.Spec.StaticRoutes) ||
!reflect.DeepEqual(oldVpc.Spec.PolicyRoutes, newVpc.Spec.PolicyRoutes) ||
!reflect.DeepEqual(oldVpc.Spec.VpcPeerings, newVpc.Spec.VpcPeerings) ||
!reflect.DeepEqual(oldVpc.Annotations, newVpc.Annotations) {
klog.V(3).Infof("enqueue update vpc %s", key)
c.addOrUpdateVpcQueue.Add(key)
Expand Down Expand Up @@ -269,6 +271,27 @@ func (c *Controller) handleAddOrUpdateVpc(key string) error {
return err
}

var newPeers []string
for _, peering := range vpc.Spec.VpcPeerings {
if err = util.CheckCidrs(peering.LocalConnectIP); err != nil {
klog.Errorf("invalid cidr %s", peering.LocalConnectIP)
return err
}
newPeers = append(newPeers, peering.RemoteVpc)
if err := c.ovnClient.CreatePeerRouterPort(vpc.Name, peering.RemoteVpc, peering.LocalConnectIP); err != nil {
klog.Errorf("failed to create peer router port for vpc %s, %v", vpc.Name, err)
return err
}
}
for _, oldPeer := range vpc.Status.VpcPeerings {
if !util.ContainsString(newPeers, oldPeer) {
if err = c.ovnClient.DeleteLogicalRouterPort(fmt.Sprintf("%s-%s", vpc.Name, oldPeer)); err != nil {
klog.Errorf("failed to delete peer router port for vpc %s, %v", vpc.Name, err)
return err
}
}
}

if vpc.Name != util.DefaultVpc {
// handle static route
existRoute, err := c.ovnClient.GetStaticRouteList(vpc.Name)
Expand Down Expand Up @@ -323,6 +346,7 @@ func (c *Controller) handleAddOrUpdateVpc(key string) error {

vpc.Status.Router = key
vpc.Status.Standby = true
vpc.Status.VpcPeerings = newPeers
if c.config.EnableLb {
vpcLb, err := c.addLoadBalancer(key)
if err != nil {
Expand Down
35 changes: 35 additions & 0 deletions pkg/ovs/ovn-nbctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,41 @@ func (c Client) createRouterPort(ls, lr, ip, mac string) error {
return nil
}

func (c Client) CreatePeerRouterPort(localRouter, remoteRouter, localRouterPortIP string) error {
localRouterPort := fmt.Sprintf("%s-%s", localRouter, remoteRouter)
remoteRouterPort := fmt.Sprintf("%s-%s", remoteRouter, localRouter)

// check router port exist, because '--may-exist' may not work for router port
results, err := c.ListLogicalEntity("logical_router_port", fmt.Sprintf("name=%s", localRouterPort))
if err != nil {
klog.Errorf("failed to list router port %s, %v", localRouterPort, err)
return err
}
if len(results) == 0 {
ipStr := strings.Split(localRouterPortIP, ",")
if len(ipStr) == 2 {
_, err = c.ovnNbCommand(MayExist, "lrp-add", localRouter, localRouterPort, util.GenerateMac(), ipStr[0], ipStr[1], "--",
"set", "logical_router_port", localRouterPort, fmt.Sprintf("peer=%s", remoteRouterPort))
} else {
_, err = c.ovnNbCommand(MayExist, "lrp-add", localRouter, localRouterPort, util.GenerateMac(), ipStr[0], "--",
"set", "logical_router_port", localRouterPort, fmt.Sprintf("peer=%s", remoteRouterPort))
}
if err != nil {
klog.Errorf("failed to create router port %s: %v", localRouterPort, err)
return err
}
}

_, err = c.ovnNbCommand("set", "logical_router_port", localRouterPort,
fmt.Sprintf("networks=%s", strings.ReplaceAll(localRouterPortIP, ",", " ")))

if err != nil {
klog.Errorf("failed to set router port %s: %v", localRouterPort, err)
return err
}
return nil
}

type StaticRoute struct {
Policy string
CIDR string
Expand Down
13 changes: 13 additions & 0 deletions yamls/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,15 @@ spec:
type: string
type: object
type: array
vpcPeerings:
items:
properties:
remoteVpc:
type: string
localConnectIP:
type: string
type: object
type: array
type: object
status:
properties:
Expand Down Expand Up @@ -458,6 +467,10 @@ spec:
items:
type: string
type: array
vpcPeerings:
items:
type: string
type: array
tcpLoadBalancer:
type: string
tcpSessionLoadBalancer:
Expand Down

0 comments on commit a34bb35

Please sign in to comment.