Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/fabric/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ func run(cmd *cobra.Command, _ []string) error {
mgr.GetClient(),
mgr.GetScheme(),
mgr.GetEventRecorder("route-binding-controller"),
"",
nil,
)

if err := rcr.SetupWithManager(cmd.Context(), mgr, routeTargetRef,
Expand Down
13 changes: 13 additions & 0 deletions cmd/gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ func run(cmd *cobra.Command, _ []string) error {
}
}

// Check if the number of interfaces is valid (must be at least 1).
if connoptions.GwOptions.NumInterfaces < 1 {
return fmt.Errorf("invalid number of interfaces (%d): must be at least 1", connoptions.GwOptions.NumInterfaces)
}

// Enable ip_forwarding.
if err = kernel.EnableIPForwarding(); err != nil {
return err
Expand Down Expand Up @@ -215,11 +220,19 @@ func run(cmd *cobra.Command, _ []string) error {
Name: connoptions.GwOptions.PodName,
Namespace: connoptions.GwOptions.Namespace,
}
tunnelName := tunnel.TunnelInterfaceName

interfaceNames := make([]string, connoptions.GwOptions.NumInterfaces)
for i := range connoptions.GwOptions.NumInterfaces {
interfaceNames[i] = tunnel.GetTunnelName(i)
}

rcr := route.NewRouteConfigurationBindingReconciler(
mgr.GetClient(),
mgr.GetScheme(),
mgr.GetEventRecorder("route-binding-controller"),
tunnelName,
interfaceNames,
)

if err := rcr.SetupWithManager(cmd.Context(), mgr, routeTargetRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ spec:
- --enable-nft-monitor={{ .Values.networking.gatewayTemplates.nftablesMonitor }}
- --enable-route-monitor={{ .Values.networking.gatewayTemplates.routeMonitor }}
- --enable-multipath-hash-policy={{ printf "{{ if gt (len .Spec.Endpoint.Ports) 1 }}true{{ else }}false{{ end }}" }}
- --num-interfaces={{ "{{ if .Spec.Endpoint.Ports }}{{ len .Spec.Endpoint.Ports }}{{ else }}1{{ end }}" }}
{{- if .Values.networking.gatewayTemplates.container.gateway.extraArgs }}
{{- toYaml .Values.networking.gatewayTemplates.container.gateway.extraArgs | nindent 16 }}
{{- end }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ spec:
- --enable-nft-monitor={{ .Values.networking.gatewayTemplates.nftablesMonitor }}
- --enable-route-monitor={{ .Values.networking.gatewayTemplates.routeMonitor }}
- --enable-multipath-hash-policy={{ printf "{{ if gt (len .Spec.Endpoint.Ports) 1 }}true{{ else }}false{{ end }}" }}
- --num-interfaces={{ "{{ if .Spec.Endpoint.Ports }}{{ len .Spec.Endpoint.Ports }}{{ else }}1{{ end }}" }}
{{- if .Values.networking.gatewayTemplates.container.gateway.extraArgs }}
{{- toYaml .Values.networking.gatewayTemplates.container.gateway.extraArgs | nindent 16 }}
{{- end }}
Expand Down
3 changes: 3 additions & 0 deletions pkg/gateway/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ const (
// gateway pod's network namespace; (2) this is meaningful only if the gateway uses multiple
// parallel tunnels to exchange date with its remote endpoint.
FlagNameEnableMultipathHashPolicy FlagName = "enable-multipath-hash-policy"
// FlagNameNumInterfaces is the number of WireGuard interfaces available to the gateway.
FlagNameNumInterfaces FlagName = "num-interfaces"
)

// RequiredFlags contains the list of the mandatory flags.
Expand Down Expand Up @@ -140,6 +142,7 @@ func InitFlags(flagset *pflag.FlagSet, opts *Options) {
flagset.Var(&opts.MinimumKernelVersion, FlagNameMinimumKernelVersion.String(), "Minimum kernel version required by Liqo")
flagset.BoolVar(&opts.EnableMultipathHashPolicy, FlagNameEnableMultipathHashPolicy.String(), false,
"Set fib_multipath_hash_policy=1 to use 5-tuple hashing for multipath routing")
flagset.IntVar(&opts.NumInterfaces, FlagNameNumInterfaces.String(), 1, "Number of WireGuard interfaces")
}

// MarkFlagsRequired marks the flags as required.
Expand Down
1 change: 1 addition & 0 deletions pkg/gateway/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Options struct {
DisableKernelVersionCheck bool
MinimumKernelVersion kernelversion.KernelVersion
EnableMultipathHashPolicy bool
NumInterfaces int
}

// NewOptions returns a new Options struct.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,13 @@ func forgeRouteConfigurationExtCIDRRules(internalnode *networkingv1beta1.Interna
dst := &podCIDRs[j]
rules = append(rules, networkingv1beta1.Rule{
Dst: dst,
Iif: ptr.To(tunnel.TunnelInterfaceName),
Iif: ptr.To(fmt.Sprintf("%s*", tunnel.TunnelInterfaceName)),
Routes: forgeRouteConfigurationExtCIDRRoutes(internalnode, dst),
})
}
}
rules = append(rules, networkingv1beta1.Rule{
Iif: ptr.To(tunnel.TunnelInterfaceName),
Iif: ptr.To(fmt.Sprintf("%s*", tunnel.TunnelInterfaceName)),
Routes: forgeRouteConfigurationExtCIDRRoutesIP(internalnode, ips),
})
return rules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func forgeRoutePodUpdateFunction(internalnode *networkingv1beta1.InternalNode, r

if routecfg.Spec.Table.Rules == nil || len(routecfg.Spec.Table.Rules) < 2 {
routecfg.Spec.Table.Rules = append(routecfg.Spec.Table.Rules, networkingv1beta1.Rule{})
routecfg.Spec.Table.Rules[1].Iif = ptr.To(tunnel.TunnelInterfaceName)
routecfg.Spec.Table.Rules[1].Iif = ptr.To(fmt.Sprintf("%s*", tunnel.TunnelInterfaceName))
}

if existingroute, exists := routeContainsPod(pod, &routecfg.Spec.Table.Rules[1]); exists {
Expand Down
56 changes: 46 additions & 10 deletions pkg/route/routeconfigurationbinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/events"
"k8s.io/klog/v2"
"k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -48,15 +49,23 @@ type RouteConfigurationBindingReconciler struct {
client.Client
Scheme *runtime.Scheme
EventsRecorder events.EventRecorder
// TunnelName is the base name used to build the placeholder ("<TunnelName>*")
// that marks rules to be expanded per tunnel interface.
TunnelName string
// TunnelInterfaceNames are the concrete tunnel interface names used to expand
// placeholder rules.
TunnelInterfaceNames []string
}

// NewRouteConfigurationBindingReconciler returns a new RouteConfigurationBindingReconciler.
func NewRouteConfigurationBindingReconciler(cl client.Client, s *runtime.Scheme,
er events.EventRecorder) *RouteConfigurationBindingReconciler {
er events.EventRecorder, tunnelName string, tunnelInterfaceNames []string) *RouteConfigurationBindingReconciler {
return &RouteConfigurationBindingReconciler{
Client: cl,
Scheme: s,
EventsRecorder: er,
Client: cl,
Scheme: s,
EventsRecorder: er,
TunnelName: tunnelName,
TunnelInterfaceNames: tunnelInterfaceNames,
}
}

Expand Down Expand Up @@ -143,13 +152,15 @@ func (r *RouteConfigurationBindingReconciler) Reconcile(ctx context.Context, req
return ctrl.Result{}, fmt.Errorf("getting the table ID: %w", err)
}

expandedRules := expandRules(routecfg.Spec.Table.Rules, r.TunnelName, r.TunnelInterfaceNames)

klog.V(4).Infof("Applying routeconfigurationbinding %s (routecfg %s)", req.String(), routecfg.Name)

existingRules, err := GetRulesByTableID(tableID)
if err != nil {
return ctrl.Result{}, fmt.Errorf("listing existing rules: %w", err)
}
if err = CleanRules(routecfg.Spec.Table.Rules, existingRules); err != nil {
if err = CleanRules(expandedRules, existingRules); err != nil {
return ctrl.Result{}, fmt.Errorf("cleaning rules: %w", err)
}

Expand All @@ -159,8 +170,8 @@ func (r *RouteConfigurationBindingReconciler) Reconcile(ctx context.Context, req
}

allRoutes := []networkingv1beta1.Route{}
for i := range routecfg.Spec.Table.Rules {
allRoutes = append(allRoutes, routecfg.Spec.Table.Rules[i].Routes...)
for i := range expandedRules {
allRoutes = append(allRoutes, expandedRules[i].Routes...)
}
if err = CleanRoutes(allRoutes, existingRoutes); err != nil {
return ctrl.Result{}, fmt.Errorf("cleaning routes: %w", err)
Expand All @@ -175,11 +186,11 @@ func (r *RouteConfigurationBindingReconciler) Reconcile(ctx context.Context, req
// NOT in the desired spec, while Ensure*Presence only looks up entries that ARE in the desired
// spec, so the two never operate on the same rows and the stale snapshot cannot cause a wrong
// exists/not-exists result. Re-fetching here would just be a redundant netlink list.
for i := range routecfg.Spec.Table.Rules {
if err = EnsureRulePresence(&routecfg.Spec.Table.Rules[i], tableID, existingRules); err != nil {
for _, rule := range expandedRules {
if err = EnsureRulePresence(&rule, tableID, existingRules); err != nil {
return ctrl.Result{}, fmt.Errorf("ensuring rule presence: %w", err)
}
if err := EnsureRoutesPresence(routecfg.Spec.Table.Rules[i].Routes, tableID, existingRoutes); err != nil {
if err := EnsureRoutesPresence(rule.Routes, tableID, existingRoutes); err != nil {
if errors.Is(err, ErrNetworkUnreachable) {
klog.Warningf("Network is unreachable for routeconfigurationbinding %s, requeuing: %v", req.String(), err)
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
Expand Down Expand Up @@ -331,3 +342,28 @@ func cleanupBinding(ctx context.Context, cl client.Client, binding *networkingv1
klog.Infof("Shutdown cleanup: removed finalizer from RouteConfigurationBinding %s/%s",
binding.Namespace, binding.Name)
}

// expandRules expands the existing rules by creating a specialized rule for each active
// network interface that matches the provided tunnel name prefix (acting as a placeholder).
func expandRules(rules []networkingv1beta1.Rule, tunnelName string, tunnelInterfaceNames []string) []networkingv1beta1.Rule {
if tunnelName == "" && len(tunnelInterfaceNames) == 0 {
return rules
}
expandedRules := []networkingv1beta1.Rule{}
placeholder := tunnelName + "*"

for i := range rules {
rule := rules[i]

if rule.Iif != nil && *rule.Iif == placeholder {
for _, iface := range tunnelInterfaceNames {
newRule := rule
newRule.Iif = ptr.To(iface)
expandedRules = append(expandedRules, newRule)
}
} else {
expandedRules = append(expandedRules, rule)
}
}
return expandedRules
}
Loading