Skip to content

Commit f8835ef

Browse files
authored
Ovn nat 1 (#3095)
* add ovn nat gw webhook * simplify ovn eip fip finalizer * add shared eip e2e * fix name * auto managed external routes * add normal route and bfd route test e2e * vpc enable auto manage normal static routes
1 parent 5704dae commit f8835ef

26 files changed

+1033
-670
lines changed

charts/templates/kube-ovn-crd.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,9 @@ spec:
868868
- jsonPath: .status.type
869869
name: Type
870870
type: string
871+
- jsonPath: .status.nat
872+
name: Nat
873+
type: string
871874
- jsonPath: .status.ready
872875
name: Ready
873876
type: boolean
@@ -880,6 +883,8 @@ spec:
880883
properties:
881884
type:
882885
type: string
886+
nat:
887+
type: string
883888
ready:
884889
type: boolean
885890
v4Ip:

dist/images/install.sh

+5
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,9 @@ spec:
14071407
- jsonPath: .status.type
14081408
name: Type
14091409
type: string
1410+
- jsonPath: .status.nat
1411+
name: Nat
1412+
type: string
14101413
- jsonPath: .status.ready
14111414
name: Ready
14121415
type: boolean
@@ -1419,6 +1422,8 @@ spec:
14191422
properties:
14201423
type:
14211424
type: string
1425+
nat:
1426+
type: string
14221427
ready:
14231428
type: boolean
14241429
v4Ip:

mocks/pkg/ovs/interface.go

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/kubeovn/v1/types.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,10 @@ type OvnEipSpec struct {
949949
V6Ip string `json:"v6Ip"`
950950
MacAddress string `json:"macAddress"`
951951
Type string `json:"type"`
952-
// usage type: fip, snat, lrp, node external gw
952+
// usage type: eip, lrp, node external gw
953+
// eip: only used by nat, fip, snat, dnat, all the nat type will record int the eip status
954+
// lrp: logical router port
955+
// node external gw: is lsp, in the case of bfd session between lrp and lsp, the lsp is on the node as external gateway
953956
}
954957

955958
// OvnEipCondition describes the state of an object at a certain point.
@@ -964,6 +967,7 @@ type OvnEipStatus struct {
964967
Conditions []OvnEipCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
965968

966969
Type string `json:"type" patchStrategy:"merge"`
970+
Nat string `json:"nat" patchStrategy:"merge"`
967971
Ready bool `json:"ready" patchStrategy:"merge"`
968972
V4Ip string `json:"v4Ip" patchStrategy:"merge"`
969973
V6Ip string `json:"v6Ip" patchStrategy:"merge"`

pkg/controller/external-gw.go

-5
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,6 @@ func (c *Controller) updateDefaultVpcExternal(enableExternal bool) error {
293293
klog.Errorf("failed to patch vpc %s, %v", c.config.ClusterRouter, err)
294294
return err
295295
}
296-
lrpEipName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
297-
if err := c.patchLrpOvnEipEnableBfdLabel(lrpEipName, vpc.Spec.EnableBfd); err != nil {
298-
klog.Errorf("failed to patch label for lrp %s, %v", lrpEipName, err)
299-
return err
300-
}
301296
}
302297
return nil
303298
}

pkg/controller/node.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ func (c *Controller) addNodeGwStaticRoute() error {
10461046
if util.CheckProtocol(cidrBlock) != util.CheckProtocol(nextHop) {
10471047
continue
10481048
}
1049-
if err := c.ovnClient.AddLogicalRouterStaticRoute(c.config.ClusterRouter, util.MainRouteTable, ovnnb.LogicalRouterStaticRoutePolicyDstIP, cidrBlock, nextHop); err != nil {
1049+
if err := c.ovnClient.AddLogicalRouterStaticRoute(c.config.ClusterRouter, util.MainRouteTable, ovnnb.LogicalRouterStaticRoutePolicyDstIP, cidrBlock, nil, nextHop); err != nil {
10501050
klog.Errorf("failed to add static route for node gw: %v", err)
10511051
return err
10521052
}

pkg/controller/ovn_dnat.go

+75-88
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import (
99
"github.com/ovn-org/libovsdb/ovsdb"
1010
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/labels"
1213
"k8s.io/apimachinery/pkg/types"
1314
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1415
"k8s.io/client-go/tools/cache"
1516
"k8s.io/klog/v2"
16-
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1717

1818
kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
1919
"github.com/kubeovn/kube-ovn/pkg/util"
@@ -41,14 +41,9 @@ func (c *Controller) enqueueUpdateOvnDnatRule(old, new interface{}) {
4141
oldDnat := old.(*kubeovnv1.OvnDnatRule)
4242
newDnat := new.(*kubeovnv1.OvnDnatRule)
4343
if !newDnat.DeletionTimestamp.IsZero() {
44-
if len(newDnat.Finalizers) == 0 {
45-
// avoid delete dnat twice
46-
return
47-
} else {
48-
klog.V(3).Infof("enqueue del ovn dnat %s", key)
49-
c.delOvnDnatRuleQueue.Add(key)
50-
return
51-
}
44+
klog.Infof("enqueue del ovn dnat %s", key)
45+
c.delOvnDnatRuleQueue.Add(key)
46+
return
5247
}
5348

5449
if oldDnat.Spec.OvnEip != newDnat.Spec.OvnEip {
@@ -60,7 +55,7 @@ func (c *Controller) enqueueUpdateOvnDnatRule(old, new interface{}) {
6055
oldDnat.Spec.IpName != newDnat.Spec.IpName ||
6156
oldDnat.Spec.InternalPort != newDnat.Spec.InternalPort ||
6257
oldDnat.Spec.ExternalPort != newDnat.Spec.ExternalPort {
63-
klog.V(3).Infof("enqueue update dnat %s", key)
58+
klog.Infof("enqueue update dnat %s", key)
6459
c.updateOvnDnatRuleQueue.Add(key)
6560
}
6661
}
@@ -181,6 +176,27 @@ func (c *Controller) processNextDeleteOvnDnatRuleWorkItem() bool {
181176
return true
182177
}
183178

179+
func (c *Controller) isOvnDnatDuplicated(eipName, dnatName, externalPort string) (bool, error) {
180+
// check if eip:external port already used
181+
dnats, err := c.ovnDnatRulesLister.List(labels.SelectorFromSet(labels.Set{
182+
util.VpcDnatEPortLabel: externalPort,
183+
}))
184+
if err != nil {
185+
if !k8serrors.IsNotFound(err) {
186+
return false, err
187+
}
188+
}
189+
if len(dnats) != 0 {
190+
for _, d := range dnats {
191+
if d.Name != dnatName && d.Spec.OvnEip == eipName {
192+
err = fmt.Errorf("failed to create dnat %s, duplicate, same eip %s, same external port '%s' is using by dnat %s", dnatName, eipName, externalPort, d.Name)
193+
return true, err
194+
}
195+
}
196+
}
197+
return false, nil
198+
}
199+
184200
func (c *Controller) handleAddOvnDnatRule(key string) error {
185201
cachedDnat, err := c.ovnDnatRulesLister.Get(key)
186202
if err != nil {
@@ -230,6 +246,16 @@ func (c *Controller) handleAddOvnDnatRule(key string) error {
230246
return err
231247
}
232248

249+
if cachedEip.Status.Type != "" && cachedEip.Status.Type != util.NatUsingEip {
250+
err = fmt.Errorf("ovn eip %s type is not %s, can not use", cachedEip.Name, util.NatUsingEip)
251+
return err
252+
}
253+
254+
if _, err := c.isOvnDnatDuplicated(eipName, key, cachedDnat.Spec.ExternalPort); err != nil {
255+
klog.Error("failed to create dnat %s, %v", cachedDnat.Name, err)
256+
return err
257+
}
258+
233259
subnet, err := c.subnetsLister.Get(subnetName)
234260
if err != nil {
235261
klog.Errorf("failed to get vpc subnet %s, %v", subnetName, err)
@@ -243,27 +269,17 @@ func (c *Controller) handleAddOvnDnatRule(key string) error {
243269
}
244270

245271
vpcName := subnet.Spec.Vpc
246-
if cachedEip.Status.Type != "" && cachedEip.Status.Type != util.DnatUsingEip {
247-
err = fmt.Errorf("failed to create ovn dnat %s, eip '%s' is using by %s", key, eipName, cachedEip.Spec.Type)
248-
return err
249-
}
250-
251272
if err = c.patchOvnDnatStatus(key, vpcName, cachedEip.Status.V4Ip,
252273
internalV4Ip, mac, false); err != nil {
253274
klog.Errorf("failed to patch status for dnat %s, %v", key, err)
254275
return err
255276
}
256277

257-
if err = c.handleAddOvnEipFinalizer(cachedEip, util.OvnDnatUseEipFinalizer); err != nil {
278+
if err = c.handleAddOvnEipFinalizer(cachedEip, util.OvnEipFinalizer); err != nil {
258279
klog.Errorf("failed to add finalizer for ovn eip, %v", err)
259280
return err
260281
}
261282

262-
if err = c.handleAddOvnDnatFinalizer(cachedDnat); err != nil {
263-
klog.Errorf("failed to handle finalizer for ovn dnat, %v", err)
264-
return err
265-
}
266-
267283
if err = c.AddDnatRule(vpcName, cachedDnat.Name, cachedEip.Status.V4Ip, internalV4Ip,
268284
cachedDnat.Spec.ExternalPort, cachedDnat.Spec.InternalPort, cachedDnat.Spec.Protocol); err != nil {
269285
klog.Errorf("failed to create v4 dnat, %v", err)
@@ -287,7 +303,7 @@ func (c *Controller) handleAddOvnDnatRule(key string) error {
287303
return err
288304
}
289305

290-
if err = c.patchOvnEipNat(eipName, util.DnatUsingEip); err != nil {
306+
if err = c.patchOvnEipStatus(eipName, true); err != nil {
291307
klog.Errorf("failed to patch status for eip %s, %v", key, err)
292308
return err
293309
}
@@ -307,33 +323,19 @@ func (c *Controller) handleDelOvnDnatRule(key string) error {
307323

308324
eipName := cachedDnat.Spec.OvnEip
309325
if len(eipName) == 0 {
310-
klog.Errorf("failed to delete ovn dnat, should set eip")
311-
}
312-
313-
cachedEip, err := c.GetOvnEip(eipName)
314-
if err != nil {
315-
klog.Errorf("failed to get eip, %v", err)
326+
err := fmt.Errorf("failed to create fip rule, should set eip")
327+
klog.Error(err)
316328
return err
317329
}
330+
318331
if cachedDnat.Status.Vpc != "" && cachedDnat.Status.V4Eip != "" && cachedDnat.Status.ExternalPort != "" {
319332
if err = c.DelDnatRule(cachedDnat.Status.Vpc, cachedDnat.Name,
320333
cachedDnat.Status.V4Eip, cachedDnat.Status.ExternalPort); err != nil {
321334
klog.Errorf("failed to delete dnat, %v", err)
322335
return err
323336
}
324337
}
325-
326-
if err = c.handleDelOvnEipFinalizer(cachedEip, util.OvnDnatUseEipFinalizer); err != nil {
327-
klog.Errorf("failed to handle remove finalizer from ovn eip, %v", err)
328-
return err
329-
}
330338
c.resetOvnEipQueue.Add(cachedDnat.Spec.OvnEip)
331-
332-
if err = c.handleDelOvnDnatFinalizer(cachedDnat); err != nil {
333-
klog.Errorf("failed to handle remove finalizer from ovn dnat, %v", err)
334-
return err
335-
}
336-
337339
return nil
338340
}
339341

@@ -381,6 +383,16 @@ func (c *Controller) handleUpdateOvnDnatRule(key string) error {
381383
return err
382384
}
383385

386+
if cachedEip.Status.Type != "" && cachedEip.Status.Type != util.NatUsingEip {
387+
err = fmt.Errorf("ovn eip %s type is not %s, can not use", cachedEip.Name, util.NatUsingEip)
388+
return err
389+
}
390+
391+
if _, err := c.isOvnDnatDuplicated(eipName, key, cachedDnat.Spec.ExternalPort); err != nil {
392+
klog.Error("failed to update dnat %s, %v", cachedDnat.Name, err)
393+
return err
394+
}
395+
384396
subnet, err := c.subnetsLister.Get(subnetName)
385397
if err != nil {
386398
klog.Errorf("failed to get vpc subnet %s, %v", subnetName, err)
@@ -440,31 +452,6 @@ func (c *Controller) handleUpdateOvnDnatRule(key string) error {
440452
return nil
441453
}
442454

443-
func (c *Controller) handleAddOvnDnatFinalizer(cachedDnat *kubeovnv1.OvnDnatRule) error {
444-
if cachedDnat.DeletionTimestamp.IsZero() {
445-
if util.ContainsString(cachedDnat.Finalizers, util.ControllerName) {
446-
return nil
447-
}
448-
}
449-
450-
newDnat := cachedDnat.DeepCopy()
451-
controllerutil.AddFinalizer(newDnat, util.ControllerName)
452-
patch, err := util.GenerateMergePatchPayload(cachedDnat, newDnat)
453-
if err != nil {
454-
return err
455-
}
456-
457-
if _, err := c.config.KubeOvnClient.KubeovnV1().OvnDnatRules().Patch(context.Background(), cachedDnat.Name,
458-
types.MergePatchType, patch, metav1.PatchOptions{}, ""); err != nil {
459-
if k8serrors.IsNotFound(err) {
460-
return nil
461-
}
462-
klog.Errorf("failed to add finalizer for ovn dnat '%s', %v", cachedDnat.Name, err)
463-
return err
464-
}
465-
return nil
466-
}
467-
468455
func (c *Controller) patchOvnDnatAnnotations(key, eipName string) error {
469456
oriDnat, err := c.ovnDnatRulesLister.Get(key)
470457
if err != nil {
@@ -510,8 +497,31 @@ func (c *Controller) patchOvnDnatStatus(key, vpcName, v4Eip, podIp, podMac strin
510497
}
511498
return err
512499
}
513-
514500
dnat := oriDnat.DeepCopy()
501+
needUpdateLabel := false
502+
var op string
503+
if len(dnat.Labels) == 0 {
504+
op = "add"
505+
needUpdateLabel = true
506+
dnat.Labels = map[string]string{
507+
util.EipV4IpLabel: v4Eip,
508+
}
509+
} else if dnat.Labels[util.EipV4IpLabel] != v4Eip {
510+
op = "replace"
511+
needUpdateLabel = true
512+
dnat.Labels[util.EipV4IpLabel] = v4Eip
513+
}
514+
if needUpdateLabel {
515+
patchPayloadTemplate := `[{ "op": "%s", "path": "/metadata/labels", "value": %s }]`
516+
raw, _ := json.Marshal(dnat.Labels)
517+
patchPayload := fmt.Sprintf(patchPayloadTemplate, op, raw)
518+
if _, err := c.config.KubeOvnClient.KubeovnV1().OvnDnatRules().Patch(context.Background(), dnat.Name,
519+
types.JSONPatchType, []byte(patchPayload), metav1.PatchOptions{}); err != nil {
520+
klog.Errorf("failed to patch label for ovn dnat %s, %v", dnat.Name, err)
521+
return err
522+
}
523+
}
524+
515525
var changed bool
516526
if dnat.Status.Ready != ready {
517527
dnat.Status.Ready = ready
@@ -563,29 +573,6 @@ func (c *Controller) patchOvnDnatStatus(key, vpcName, v4Eip, podIp, podMac strin
563573
return nil
564574
}
565575

566-
func (c *Controller) handleDelOvnDnatFinalizer(cachedDnat *kubeovnv1.OvnDnatRule) error {
567-
if len(cachedDnat.Finalizers) == 0 {
568-
return nil
569-
}
570-
571-
newDnat := cachedDnat.DeepCopy()
572-
controllerutil.RemoveFinalizer(newDnat, util.ControllerName)
573-
patch, err := util.GenerateMergePatchPayload(cachedDnat, newDnat)
574-
if err != nil {
575-
return err
576-
}
577-
578-
if _, err := c.config.KubeOvnClient.KubeovnV1().OvnDnatRules().Patch(context.Background(), cachedDnat.Name,
579-
types.MergePatchType, patch, metav1.PatchOptions{}, ""); err != nil {
580-
if k8serrors.IsNotFound(err) {
581-
return nil
582-
}
583-
klog.Errorf("failed to remove finalizer from ovn dnat '%s', %v", cachedDnat.Name, err)
584-
return err
585-
}
586-
return nil
587-
}
588-
589576
func (c *Controller) AddDnatRule(vpcName, dnatName, externalIp, internalIp, externalPort, internalPort, protocol string) error {
590577
externalEndpoint := net.JoinHostPort(externalIp, externalPort)
591578
internalEndpoint := net.JoinHostPort(internalIp, internalPort)

0 commit comments

Comments
 (0)