Skip to content

Commit

Permalink
IPTables module support for NatMapping resource
Browse files Browse the repository at this point in the history
This PR enables the IPTables module to manage NatMapping resource similarly to TunnelEndpoints.  A new chper-cluster chain for NAT mappings has been added. A new functions to ensure rules extracted from NatMapping resource has been added.
  • Loading branch information
davidefalcone1 committed Jun 22, 2021
1 parent 76b317d commit 1999b3d
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 159 deletions.
7 changes: 6 additions & 1 deletion internal/liqonet/tunnel-operator/tunnel-operator.go
Expand Up @@ -168,6 +168,11 @@ func (tc *TunnelController) Reconcile(ctx context.Context, req ctrl.Request) (ct
return nil
}
var unconfigGWNetns = func(netNamespace ns.NetNS) error {
if err := tc.IPTHandler.RemoveIPTablesConfigurationPerCluster(tep); err != nil {
klog.Errorf("an error occurred while remove cluster %s IPTables configuration: %s",
tep.Spec.ClusterID, err.Error())
return err
}
if err := tc.disconnectFromPeer(tep); err != nil {
return err
}
Expand Down Expand Up @@ -360,7 +365,7 @@ func (tc *TunnelController) EnsureIPTablesRulesPerCluster(tep *netv1alpha1.Tunne
tc.Eventf(tep, "Warning", "Processing", "unable to insert iptables rules: %v", err)
return err
}
if err := tc.EnsurePreroutingRules(tep); err != nil {
if err := tc.EnsurePreroutingRulesPerTep(tep); err != nil {
klog.Errorf("%s -> an error occurred while inserting iptables prerouting rules for the remote peer: %s", clusterID, err.Error())
tc.Eventf(tep, "Warning", "Processing", "unable to insert iptables rules: %v", err)
return err
Expand Down
89 changes: 76 additions & 13 deletions pkg/liqonet/iptables/iptables.go
Expand Up @@ -31,6 +31,8 @@ const (
liqonetForwardingClusterChainPrefix = "LIQO-FRWD-CLS-"
// liqonetInputClusterChainPrefix prefix used to name the input chains for a specific cluster.
liqonetInputClusterChainPrefix = "LIQO-INPT-CLS-"
// liqonetPreRoutingMappingClusterChainPrefix prefix used to name the prerouting mapping chain for a specific cluster.
liqonetPreRoutingMappingClusterChainPrefix = "LIQO-PRRT-MAP-CLS-"
// natTable constant used for the "nat" table.
natTable = "nat"
// filterTable constant used for the "filter" table.
Expand All @@ -47,6 +49,8 @@ const (
MASQUERADE = "MASQUERADE"
// SNAT action constant.
SNAT = "SNAT"
// DNAT action constant.
DNAT = "DNAT"
// NETMAP action constant.
NETMAP = "NETMAP"
// ACCEPT action constant.
Expand All @@ -55,8 +59,12 @@ const (
podCIDR = "PodCIDR"
// localPodCIDR is a field of the TunnelEndpoint resource.
localPodCIDR = "LocalPodCIDR"
// localExternalCIDR is a field of the TunnelEndpoint resource.
localExternalCIDR = "LocalExternalCIDR"
// localNATPodCIDR is a field of the TunnelEndpoint resource.
localNATPodCIDR = "LocalNATPodCIDR"
// localNATExternalCIDR is a field of the TunnelEndpoint resource.
localNATExternalCIDR = "LocalNATExternalCIDR"
// remoteNATPodCIDR is a field of the TunnelEndpoint resource.
remoteNATPodCIDR = "RemoteNATPodCIDR"
)
Expand Down Expand Up @@ -290,12 +298,14 @@ func (h IPTHandler) getExistingChainRules(clusterID, chain string) ([]string, er
return existingChainRules, nil
}

func getChainsPerCluster(clusterID string) map[string]string {
chains := make(map[string]string)
chains[forwardChain] = getClusterForwardChain(clusterID)
chains[inputChain] = getClusterInputChain(clusterID)
chains[postroutingChain] = getClusterPostRoutingChain(clusterID)
chains[preroutingChain] = getClusterPreRoutingChain(clusterID)
func getChainsPerCluster(clusterID string) []string {
chains := []string{
getClusterForwardChain(clusterID),
getClusterInputChain(clusterID),
getClusterPostRoutingChain(clusterID),
getClusterPreRoutingChain(clusterID),
getClusterPreRoutingMappingChain(clusterID),
}
return chains
}

Expand Down Expand Up @@ -327,6 +337,7 @@ func getTableFromChain(chain string) string {
return filterTable
}
if strings.Contains(chain, liqonetPostroutingClusterChainPrefix) ||
strings.Contains(chain, liqonetPreRoutingMappingClusterChainPrefix) ||
strings.Contains(chain, liqonetPreroutingClusterChainPrefix) {
return natTable
}
Expand Down Expand Up @@ -409,8 +420,8 @@ func (h IPTHandler) removeChainsPerCluster(clusterID string) error {
chains := getChainsPerCluster(clusterID)
// For each cluster chain, check if it exists.
// If it does exist, then remove it. Otherwise do nothing.
for wrapperChain, chain := range chains {
if getTableFromChain(wrapperChain) == natTable && slice.ContainsString(existingChainsNAT, chain, nil) {
for _, chain := range chains {
if getTableFromChain(chain) == natTable && slice.ContainsString(existingChainsNAT, chain, nil) {
// Check if chain exists
if !slice.ContainsString(existingChainsNAT, chain, nil) {
continue
Expand All @@ -424,7 +435,7 @@ func (h IPTHandler) removeChainsPerCluster(clusterID string) error {
klog.Infof("Deleted chain %s in table %s", chain, getTableFromChain(chain))
continue
}
if getTableFromChain(wrapperChain) == filterTable && slice.ContainsString(existingChainsFilter, chain, nil) {
if getTableFromChain(chain) == filterTable && slice.ContainsString(existingChainsFilter, chain, nil) {
if !slice.ContainsString(existingChainsFilter, chain, nil) {
continue
}
Expand All @@ -450,17 +461,29 @@ func (h IPTHandler) EnsurePostroutingRules(tep *netv1alpha1.TunnelEndpoint) erro
return h.updateRulesPerChain(getClusterPostRoutingChain(clusterID), rules)
}

// EnsurePreroutingRules makes sure that the prerouting rules for a given cluster are in place and updated.
func (h IPTHandler) EnsurePreroutingRules(tep *netv1alpha1.TunnelEndpoint) error {
// EnsurePreroutingRulesPerTep makes sure that the prerouting rules extracted from a
// TunnelEndpoint resource in place and updated.
func (h IPTHandler) EnsurePreroutingRulesPerTep(tep *netv1alpha1.TunnelEndpoint) error {
clusterID := tep.Spec.ClusterID
rules, err := getPreRoutingRules(tep)
rules, err := getPreRoutingRulesPerTep(tep)
if err != nil {
return err
}
return h.updateRulesPerChain(getClusterPreRoutingChain(clusterID), rules)
}

func getPreRoutingRules(tep *netv1alpha1.TunnelEndpoint) ([]IPTableRule, error) {
// EnsurePreroutingRulesPerNm makes sure that the prerouting rules extracted from a
// NatMapping resource in place and updated.
func (h IPTHandler) EnsurePreroutingRulesPerNm(nm *netv1alpha1.NatMapping) error {
clusterID := nm.Spec.ClusterID
rules, err := getPreRoutingRulesPerNm(nm)
if err != nil {
return err
}
return h.updateRulesPerChain(getClusterPreRoutingMappingChain(clusterID), rules)
}

func getPreRoutingRulesPerTep(tep *netv1alpha1.TunnelEndpoint) ([]IPTableRule, error) {
// Check tep fields
if err := checkTep(tep); err != nil {
return nil, fmt.Errorf("invalid TunnelEndpoint resource: %w", err)
Expand All @@ -481,6 +504,25 @@ func getPreRoutingRules(tep *netv1alpha1.TunnelEndpoint) ([]IPTableRule, error)
return rules, nil
}

func getPreRoutingRulesPerNm(nm *netv1alpha1.NatMapping) ([]IPTableRule, error) {
// Check tep fields
if nm.Spec.ClusterID == "" {
return nil, &errors.WrongParameter{
Parameter: consts.ClusterIDLabelName,
Reason: errors.StringNotEmpty,
}
}

rules := make([]IPTableRule, 0)

for oldIP, newIP := range nm.Spec.ClusterMappings {
rules = append(rules,
IPTableRule{"-d", newIP, "-j", DNAT, "--to-destination", oldIP},
)
}
return rules, nil
}

// Function that returns a slice of strings that contains a given string.
func getSliceContainingString(stringSlice []string, s string) (stringsThatContainsS []string) {
stringsThatContainsS = make([]string, 0)
Expand All @@ -502,6 +544,7 @@ func (h IPTHandler) ListRulesInChain(chain string) ([]string, error) {
ruleToRemove := strings.Join([]string{"-N", chain}, " ")
for _, rule := range existingRules {
if rule != ruleToRemove {
rule = strings.ReplaceAll(rule, "/32", "")
tmp := strings.Split(rule, " ")
rules = append(rules, strings.Join(tmp[2:], " "))
}
Expand Down Expand Up @@ -683,13 +726,26 @@ func checkTep(tep *netv1alpha1.TunnelEndpoint) error {
Reason: errors.ValidCIDR,
}
}
if err := utils.IsValidCIDR(tep.Status.LocalExternalCIDR); err != nil {
return &errors.WrongParameter{
Parameter: localExternalCIDR,
Reason: errors.ValidCIDR,
}
}
if err := utils.IsValidCIDR(tep.Status.LocalNATPodCIDR); tep.Status.LocalNATPodCIDR != consts.DefaultCIDRValue &&
err != nil {
return &errors.WrongParameter{
Parameter: localNATPodCIDR,
Reason: errors.ValidCIDR,
}
}
if err := utils.IsValidCIDR(tep.Status.LocalNATExternalCIDR); tep.Status.LocalNATExternalCIDR != consts.DefaultCIDRValue &&
err != nil {
return &errors.WrongParameter{
Parameter: localNATExternalCIDR,
Reason: errors.ValidCIDR,
}
}
if err := utils.IsValidCIDR(tep.Status.RemoteNATPodCIDR); tep.Status.RemoteNATPodCIDR != consts.DefaultCIDRValue &&
err != nil {
return &errors.WrongParameter{
Expand All @@ -710,6 +766,7 @@ func getChainRulesPerCluster(tep *netv1alpha1.TunnelEndpoint) (map[string][]IPTa
}
clusterID := tep.Spec.ClusterID
localRemappedPodCIDR, remotePodCIDR := utils.GetPodCIDRS(tep)
localRemappedExternalCIDR := utils.GetExternalCIDR(tep)

// Init chain rules
chainRules := make(map[string][]IPTableRule)
Expand All @@ -726,6 +783,8 @@ func getChainRulesPerCluster(tep *netv1alpha1.TunnelEndpoint) (map[string][]IPTa
IPTableRule{"-d", remotePodCIDR, "-j", getClusterInputChain(clusterID)})
chainRules[liqonetForwardingChain] = append(chainRules[liqonetForwardingChain],
IPTableRule{"-d", remotePodCIDR, "-j", getClusterForwardChain(clusterID)})
chainRules[liqonetPreroutingChain] = append(chainRules[liqonetPreroutingChain],
IPTableRule{"-s", remotePodCIDR, "-d", localRemappedExternalCIDR, "-j", getClusterPreRoutingMappingChain(clusterID)})
if localRemappedPodCIDR != consts.DefaultCIDRValue {
// For the following rule, source is necessary
// because more remote clusters could have
Expand All @@ -752,6 +811,10 @@ func getClusterInputChain(clusterID string) string {
return fmt.Sprintf("%s%s", liqonetInputClusterChainPrefix, strings.Split(clusterID, "-")[0])
}

func getClusterPreRoutingMappingChain(clusterID string) string {
return fmt.Sprintf("%s%s", liqonetPreRoutingMappingClusterChainPrefix, strings.Split(clusterID, "-")[0])
}

// Function that returns the set of Liqo default chains.
// Value is the Liqo chain, key is the related default chain.
// Example: key: PREROUTING, value: LIQO-PREROUTING.
Expand Down

0 comments on commit 1999b3d

Please sign in to comment.