Skip to content

Commit 2d2e445

Browse files
pperiyasamyjcaamano
authored andcommitted
Reconcile namespace for network change
Since CanServeNamespace filters out namespace events for namespaces unknown to be served by this primary network, we need to reconcile namespaces once the network is reconfigured to serve a namespace. Hence this commit reconciles those namespaces and also reconciles each network policy if it contains only peer namespace selector. Signed-off-by: Periyasamy Palanisamy <[email protected]>
1 parent 259f309 commit 2d2e445

File tree

4 files changed

+228
-33
lines changed

4 files changed

+228
-33
lines changed

go-controller/pkg/ovn/base_network_controller.go

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,7 @@ type BaseNetworkController struct {
191191

192192
func (oc *BaseNetworkController) reconcile(netInfo util.NetInfo, setNodeFailed func(string)) error {
193193
// gather some information first
194-
var err error
195-
var retryNodes []*corev1.Node
194+
var reconcileNodes []string
196195
oc.localZoneNodes.Range(func(key, _ any) bool {
197196
nodeName := key.(string)
198197
wasAdvertised := util.IsPodNetworkAdvertisedAtNode(oc, nodeName)
@@ -201,41 +200,57 @@ func (oc *BaseNetworkController) reconcile(netInfo util.NetInfo, setNodeFailed f
201200
// noop
202201
return true
203202
}
204-
var node *corev1.Node
205-
node, err = oc.watchFactory.GetNode(nodeName)
206-
if err != nil {
207-
return false
208-
}
209-
retryNodes = append(retryNodes, node)
203+
reconcileNodes = append(reconcileNodes, nodeName)
210204
return true
211205
})
212-
if err != nil {
213-
return fmt.Errorf("failed to reconcile network %s: %w", oc.GetNetworkName(), err)
214-
}
215206
reconcileRoutes := oc.routeImportManager != nil && oc.routeImportManager.NeedsReconciliation(netInfo)
216207
reconcilePendingPods := !oc.IsDefault() && !oc.ReconcilableNetInfo.EqualNADs(netInfo.GetNADs()...)
208+
reconcileNamespaces := sets.NewString()
209+
if oc.IsPrimaryNetwork() {
210+
// since CanServeNamespace filters out namespace events for namespaces unknown
211+
// to be served by this primary network, we need to reconcile namespaces once
212+
// the network is reconfigured to serve a namespace.
213+
reconcileNamespaces = sets.NewString(netInfo.GetNADNamespaces()...).Difference(
214+
sets.NewString(oc.GetNADNamespaces()...))
215+
}
217216

218217
// set the new NetInfo, point of no return
219-
err = util.ReconcileNetInfo(oc.ReconcilableNetInfo, netInfo)
218+
err := util.ReconcileNetInfo(oc.ReconcilableNetInfo, netInfo)
220219
if err != nil {
221220
return fmt.Errorf("failed to reconcile network information for network %s: %v", oc.GetNetworkName(), err)
222221
}
223222

223+
oc.doReconcile(reconcileRoutes, reconcilePendingPods, reconcileNodes, setNodeFailed, reconcileNamespaces.List())
224+
225+
return nil
226+
}
227+
228+
// doReconcile performs the reconciliation after the controller NetInfo has already being
229+
// updated with the changes. What needs to be reconciled should already be known and
230+
// provided on the arguments of the method. This method returns no error and logs them
231+
// instead since once the controller NetInfo has been updated there is no point in retrying.
232+
func (oc *BaseNetworkController) doReconcile(reconcileRoutes, reconcilePendingPods bool,
233+
reconcileNodes []string, setNodeFailed func(string), reconcileNamespaces []string) {
224234
if reconcileRoutes {
225-
err = oc.routeImportManager.ReconcileNetwork(oc.GetNetworkName())
235+
err := oc.routeImportManager.ReconcileNetwork(oc.GetNetworkName())
226236
if err != nil {
227237
klog.Errorf("Failed to reconcile network %s on route import controller: %v", oc.GetNetworkName(), err)
228238
}
229239
}
230240

231-
for _, node := range retryNodes {
232-
setNodeFailed(node.Name)
241+
for _, nodeName := range reconcileNodes {
242+
setNodeFailed(nodeName)
243+
node, err := oc.watchFactory.GetNode(nodeName)
244+
if err != nil {
245+
klog.Infof("Failed to get node %s for reconciling network %s: %v", nodeName, oc.GetNetworkName(), err)
246+
continue
247+
}
233248
err = oc.retryNodes.AddRetryObjWithAddNoBackoff(node)
234249
if err != nil {
235-
klog.Errorf("Failed to retry node %s for network %s: %v", node.Name, oc.GetNetworkName(), err)
250+
klog.Errorf("Failed to retry node %s for network %s: %v", nodeName, oc.GetNetworkName(), err)
236251
}
237252
}
238-
if len(retryNodes) > 0 {
253+
if len(reconcileNodes) > 0 {
239254
oc.retryNodes.RequestRetryObjs()
240255
}
241256

@@ -245,7 +260,28 @@ func (oc *BaseNetworkController) reconcile(netInfo util.NetInfo, setNodeFailed f
245260
}
246261
}
247262

248-
return nil
263+
namespaceAdded := false
264+
for _, ns := range reconcileNamespaces {
265+
namespace, err := oc.watchFactory.GetNamespace(ns)
266+
if err != nil {
267+
klog.Infof("Failed to get namespace %s for reconciling network %s: %v", ns, oc.GetNetworkName(), err)
268+
continue
269+
}
270+
err = oc.retryNamespaces.AddRetryObjWithAddNoBackoff(namespace)
271+
if err != nil {
272+
klog.Infof("Failed to retry namespace %s for network %s: %v", ns, oc.GetNetworkName(), err)
273+
continue
274+
}
275+
namespaceAdded = true
276+
}
277+
if namespaceAdded {
278+
oc.retryNamespaces.RequestRetryObjs()
279+
}
280+
281+
err := oc.requeuePeerNamespaces(reconcileNamespaces)
282+
if err != nil {
283+
klog.Infof("Failed to retry network policy peer namespaces for network %s: %v", oc.GetNetworkName(), err)
284+
}
249285
}
250286

251287
// BaseSecondaryNetworkController structure holds per-network fields and network specific

go-controller/pkg/ovn/base_network_controller_policy.go

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
corev1 "k8s.io/api/core/v1"
1111
knet "k8s.io/api/networking/v1"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/labels"
1314
"k8s.io/apimachinery/pkg/util/sets"
1415
"k8s.io/klog/v2"
1516
utilnet "k8s.io/utils/net"
@@ -23,6 +24,7 @@ import (
2324
libovsdbutil "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/libovsdb/util"
2425
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/metrics"
2526
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb"
27+
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/retry"
2628
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
2729
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
2830
utilerrors "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util/errors"
@@ -162,6 +164,8 @@ type networkPolicy struct {
162164
localPodHandler *factory.Handler
163165
// peer namespace handlers
164166
nsHandlerList []*factory.Handler
167+
// peer namespace reconcilers
168+
reconcilePeerNamespaces []*reconcilePeerNamespaces
165169
// peerAddressSets stores PodSelectorAddressSet keys for peers that this network policy was successfully added to.
166170
// Required for cleanup.
167171
peerAddressSets []string
@@ -186,17 +190,23 @@ type networkPolicy struct {
186190
cancelableContext *util.CancelableContext
187191
}
188192

193+
type reconcilePeerNamespaces struct {
194+
retryNamespaces *retry.RetryFramework
195+
namespaceSelector *metav1.LabelSelector
196+
}
197+
189198
func NewNetworkPolicy(policy *knet.NetworkPolicy) *networkPolicy {
190199
policyTypeIngress, policyTypeEgress := getPolicyType(policy)
191200
np := &networkPolicy{
192-
name: policy.Name,
193-
namespace: policy.Namespace,
194-
ingressPolicies: make([]*gressPolicy, 0),
195-
egressPolicies: make([]*gressPolicy, 0),
196-
isIngress: policyTypeIngress,
197-
isEgress: policyTypeEgress,
198-
nsHandlerList: make([]*factory.Handler, 0),
199-
localPods: sync.Map{},
201+
name: policy.Name,
202+
namespace: policy.Namespace,
203+
ingressPolicies: make([]*gressPolicy, 0),
204+
egressPolicies: make([]*gressPolicy, 0),
205+
isIngress: policyTypeIngress,
206+
isEgress: policyTypeEgress,
207+
nsHandlerList: make([]*factory.Handler, 0),
208+
reconcilePeerNamespaces: make([]*reconcilePeerNamespaces, 0),
209+
localPods: sync.Map{},
200210
}
201211
return np
202212
}
@@ -1490,6 +1500,63 @@ func (bnc *BaseNetworkController) peerNamespaceUpdate(np *networkPolicy, gp *gre
14901500
return err
14911501
}
14921502

1503+
// requeuePeerNamespaces enqueues the namespace into network policy peer namespace
1504+
// retry framework object(s) which need to be retried immediately with add event.
1505+
func (bnc *BaseNetworkController) requeuePeerNamespaces(namespaces []string) error {
1506+
npKeys := bnc.networkPolicies.GetKeys()
1507+
var errors []error
1508+
for _, npKey := range npKeys {
1509+
err := bnc.networkPolicies.DoWithLock(npKey, func(npKey string) error {
1510+
np, ok := bnc.networkPolicies.Load(npKey)
1511+
if !ok {
1512+
return nil
1513+
}
1514+
np.RLock()
1515+
defer np.RUnlock()
1516+
var errors []error
1517+
for _, reconcilePeerNamespace := range np.reconcilePeerNamespaces {
1518+
namespaceAdded := false
1519+
for _, ns := range namespaces {
1520+
namespace, err := bnc.watchFactory.GetNamespace(ns)
1521+
if err != nil {
1522+
errors = append(errors, fmt.Errorf("failed to retrieve peer namespace %s for network policy %s on network %s: %w",
1523+
ns, npKey, bnc.GetNetworkName(), err))
1524+
continue
1525+
}
1526+
namespaceLabels := labels.Set(namespace.Labels)
1527+
peerNamespaceSelector, err := metav1.LabelSelectorAsSelector(reconcilePeerNamespace.namespaceSelector)
1528+
if err != nil {
1529+
errors = append(errors, fmt.Errorf("failed to parse peer namespace %s selector for network policy %s on network %s: %w",
1530+
ns, npKey, bnc.GetNetworkName(), err))
1531+
continue
1532+
}
1533+
// Filter out namespace when it's labels not matching with network policy peer namespace
1534+
// selector.
1535+
if !peerNamespaceSelector.Matches(namespaceLabels) {
1536+
continue
1537+
}
1538+
err = reconcilePeerNamespace.retryNamespaces.AddRetryObjWithAddNoBackoff(namespace)
1539+
if err != nil {
1540+
errors = append(errors, fmt.Errorf("failed to retry peer namespace %s for network policy %s on network %s: %w",
1541+
ns, npKey, bnc.GetNetworkName(), err))
1542+
continue
1543+
}
1544+
namespaceAdded = true
1545+
}
1546+
if namespaceAdded {
1547+
reconcilePeerNamespace.retryNamespaces.RequestRetryObjs()
1548+
}
1549+
}
1550+
return utilerrors.Join(errors...)
1551+
})
1552+
if err != nil {
1553+
errors = append(errors, fmt.Errorf("failed to retry peer namespaces for network policy %s on network %s: %w",
1554+
npKey, bnc.GetNetworkName(), err))
1555+
}
1556+
}
1557+
return utilerrors.Join(errors...)
1558+
}
1559+
14931560
// addPeerNamespaceHandler starts a watcher for PeerNamespaceSelectorType.
14941561
// Sync function and Add event for every existing namespace will be executed sequentially first, and an error will be
14951562
// returned if something fails.
@@ -1522,7 +1589,17 @@ func (bnc *BaseNetworkController) addPeerNamespaceHandler(
15221589
klog.Errorf("WatchResource failed for addPeerNamespaceHandler: %v", err)
15231590
return err
15241591
}
1525-
1592+
// Add peer namespace retry framework object into np.retryPeerNamespaces list so that
1593+
// when a new peer namespace is newly created later under UDN network, it gets reconciled
1594+
// and address set is created for the namespace. so we must reconcile it for network policy
1595+
// as well to update gress policy ACL with matching peer namespace address set.
1596+
if util.IsNetworkSegmentationSupportEnabled() && bnc.IsPrimaryNetwork() {
1597+
np.Lock()
1598+
np.reconcilePeerNamespaces = append(np.reconcilePeerNamespaces,
1599+
&reconcilePeerNamespaces{retryNamespaces: retryPeerNamespaces,
1600+
namespaceSelector: namespaceSelector})
1601+
np.Unlock()
1602+
}
15261603
np.nsHandlerList = append(np.nsHandlerList, namespaceHandler)
15271604
return nil
15281605
}
@@ -1540,6 +1617,7 @@ func (bnc *BaseNetworkController) shutdownHandlers(np *networkPolicy) {
15401617
for _, handler := range np.nsHandlerList {
15411618
bnc.watchFactory.RemoveNamespaceHandler(handler)
15421619
}
1620+
np.reconcilePeerNamespaces = make([]*reconcilePeerNamespaces, 0)
15431621
np.nsHandlerList = make([]*factory.Handler, 0)
15441622
}
15451623

go-controller/pkg/ovn/gress_policy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ func (gp *gressPolicy) addNamespaceAddressSet(name string, asf addressset.Addres
209209
return false, fmt.Errorf("cannot add peer namespace %s: failed to get address set: %v", name, err)
210210
}
211211
v4HashName, v6HashName := as.GetASHashNames()
212+
if v4HashName == "" && v6HashName == "" {
213+
// This would happen when a namespace is not yet reconciled with UDN network.
214+
return false, fmt.Errorf("cannot add peer namespace %s: address set has empty hashed name", name)
215+
}
212216
v4HashName = "$" + v4HashName
213217
v6HashName = "$" + v6HashName
214218

@@ -234,6 +238,9 @@ func (gp *gressPolicy) addNamespaceAddressSet(name string, asf addressset.Addres
234238
func (gp *gressPolicy) delNamespaceAddressSet(name string) bool {
235239
dbIDs := getNamespaceAddrSetDbIDs(name, gp.controllerName)
236240
v4HashName, v6HashName := addressset.GetHashNamesForAS(dbIDs)
241+
if v4HashName == "" && v6HashName == "" {
242+
return false
243+
}
237244
v4HashName = "$" + v4HashName
238245
v6HashName = "$" + v6HashName
239246

0 commit comments

Comments
 (0)