Skip to content

Commit

Permalink
Always enable global IPv6 forwarding
Browse files Browse the repository at this point in the history
Global forwarding works differently for IPv6:
  conf/all/forwarding - BOOLEAN
   Enable global IPv6 forwarding between all interfaces.
	  IPv4 and IPv6 work differently here; e.g. netfilter must be used
	  to control which interfaces may forward packets and which not.
https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

It is not possible to configure the IPv6 forwarding per interface by
setting the net.ipv6.conf.<ifname>.forwarding sysctl. Instead,
the opposite approach is required where the global forwarding
is enabled and an iptables rule is added to restrict it by default.

Signed-off-by: Patryk Diak <pdiak@redhat.com>
  • Loading branch information
kyrtapz committed May 22, 2024
1 parent af10d06 commit 6c4d259
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 34 deletions.
79 changes: 61 additions & 18 deletions go-controller/pkg/node/default_node_network_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"sync"
"time"

"github.com/coreos/go-iptables/iptables"
nodeipt "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/node/iptables"
kapi "k8s.io/api/core/v1"
discovery "k8s.io/api/discovery/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -789,10 +791,10 @@ func (nc *DefaultNodeNetworkController) Start(ctx context.Context) error {
}
}

// Set forwarding related sysctl parameters. initGateway() and
// Configure global forwarding settings. initGateway() and
// createNodeManagementPorts() may override forwarding sysctl
// parameters set for breth0 and mp0 interfaces down the line
if err = setGlobalForwardingRule(); err != nil {
if err = configureGlobalForwarding(); err != nil {
return err
}

Expand Down Expand Up @@ -1329,27 +1331,68 @@ func DummyNextHopIPs() []net.IP {
return nextHops
}

// setGlobalForwardingRule either enables or disables forwarding for
// all IPv4 and IPv6 interfaces by setting sysctl parameters based on
// config.Gateway.DisableForwarding
func setGlobalForwardingRule() error {
setForwardingSysctl := func(value string) error {
stdout, stderr, err := util.RunSysctl("-w", fmt.Sprintf("net.ipv4.ip_forward=%s", value), fmt.Sprintf("net.ipv6.conf.all.forwarding=%s", value))
if err != nil || stdout != fmt.Sprintf("%s\n%s", fmt.Sprintf("net.ipv4.ip_forward = %s", value), fmt.Sprintf("net.ipv6.conf.all.forwarding = %s", value)) {
return fmt.Errorf("could not set the correct forwarding value for all ipv4 and ipv6 interfaces: stdout: %v, stderr: %v, err: %v",
// configureGlobalForwarding configures the global forwarding settings.
// For IPv4 it either enables or disables forwarding for
// all interfaces based on config.Gateway.DisableForwarding.
// For IPv6 it always enables the global forwarding and adds/removes the `-A FORWARD -j DROP` rule based on
// config.Gateway.DisableForwarding.
func configureGlobalForwarding() error {
setIPv4Forwarding := func(value string) error {
stdout, stderr, err := util.RunSysctl("-w", fmt.Sprintf("net.ipv4.ip_forward=%s", value))
if err != nil || stdout != fmt.Sprintf("net.ipv4.ip_forward = %s", value) {
return fmt.Errorf("could not set the correct forwarding value for all ipv4 interfaces: stdout: %v, stderr: %v, err: %v",
stdout, stderr, err)
}
return nil
}
if config.Gateway.DisableForwarding {
err := setForwardingSysctl("0")
if err != nil {
return err

if config.IPv4Mode {
if config.Gateway.DisableForwarding {
if err := setIPv4Forwarding("0"); err != nil {
return err
}
} else {
if err := setIPv4Forwarding("1"); err != nil {
return err
}
}
} else {
err := setForwardingSysctl("1")
if err != nil {
return err
}

// Global forwarding works differently for IPv6:
// conf/all/forwarding - BOOLEAN
// Enable global IPv6 forwarding between all interfaces.
// IPv4 and IPv6 work differently here; e.g. netfilter must be used
// to control which interfaces may forward packets and which not.
// https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
//
// It is not possible to configure the IPv6 forwarding per interface by
// setting the net.ipv6.conf.<ifname>.forwarding sysctl. Instead,
// the opposite approach is required where the global forwarding
// is enabled and an iptables rule is added to restrict it by default.
if config.IPv6Mode {
if err := ip.EnableIP6Forward(); err != nil {
return fmt.Errorf("could not set the correct global forwarding value for ipv6: %v", err)
}

forwardDropRule := nodeipt.Rule{
Table: "filter",
Chain: "FORWARD",
Args: []string{
"-j", "DROP",
},
Protocol: iptables.ProtocolIPv6,
}

if config.Gateway.DisableForwarding {
// Add the default drop rule to FORWARD
if err := nodeipt.AddRules([]nodeipt.Rule{forwardDropRule}, true); err != nil {
return fmt.Errorf("failed to add the forwarding block rule: err %v", err)
}
} else {
// Remove the default drop rule from FORWARD
if err := nodeipt.DelRules([]nodeipt.Rule{forwardDropRule}); err != nil {
return fmt.Errorf("failed to remove the forwarding block rule: err %v", err)
}
}
}
return nil
Expand Down
20 changes: 10 additions & 10 deletions go-controller/pkg/node/gateway_iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,9 @@ func getGatewayForwardRules(cidrs []*net.IPNet) []nodeipt.Rule {
return returnRules
}

func getGatewayDropRules(ifName string) []nodeipt.Rule {
func getGatewayIPv4DropRules(ifName string) []nodeipt.Rule {
var dropRules []nodeipt.Rule
for _, protocol := range clusterIPTablesProtocols() {
if config.IPv4Mode {
dropRules = append(dropRules, []nodeipt.Rule{
{
Table: "filter",
Expand All @@ -376,7 +376,7 @@ func getGatewayDropRules(ifName string) []nodeipt.Rule {
"-i", ifName,
"-j", "DROP",
},
Protocol: protocol,
Protocol: iptables.ProtocolIPv4,
},
{
Table: "filter",
Expand All @@ -385,7 +385,7 @@ func getGatewayDropRules(ifName string) []nodeipt.Rule {
"-o", ifName,
"-j", "DROP",
},
Protocol: protocol,
Protocol: iptables.ProtocolIPv4,
},
}...)
}
Expand All @@ -407,18 +407,18 @@ func delExternalBridgeServiceForwardingRules(cidrs []*net.IPNet) error {
return deleteIptRules(getGatewayForwardRules(cidrs))
}

// initExternalBridgeDropRules sets up iptables rules to block forwarding
// addIPv4DropForwardingRules sets up IPv4 iptables rules to block forwarding
// in br-* interfaces (also for 2ndary bridge) - we block for v4 and v6 based on clusterStack
// -A FORWARD -i breth1 -j DROP
// -A FORWARD -o breth1 -j DROP
func initExternalBridgeDropForwardingRules(ifName string) error {
return appendIptRules(getGatewayDropRules(ifName))
func addIPv4DropForwardingRules(ifName string) error {
return appendIptRules(getGatewayIPv4DropRules(ifName))
}

// delExternalBridgeDropForwardingRules removes iptables rules which might
// delIPv4DropForwardingRules removes IPv4 iptables rules which might
// have been added to disable forwarding
func delExternalBridgeDropForwardingRules(ifName string) error {
return deleteIptRules(getGatewayDropRules(ifName))
func delIPv4DropForwardingRules(ifName string) error {
return deleteIptRules(getGatewayIPv4DropRules(ifName))
}

func getLocalGatewayFilterRules(ifname string, cidr *net.IPNet) []nodeipt.Rule {
Expand Down
7 changes: 5 additions & 2 deletions go-controller/pkg/node/gateway_localnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,15 @@ func newLocalGateway(nodeName string, hostSubnets []*net.IPNet, gwNextHops []net
if err != nil {
return err
}

// There is no need to add/remove the drop rules for IPv6
// since there is already one configured in configureGlobalForwarding
if config.Gateway.DisableForwarding {
if err := initExternalBridgeDropForwardingRules(exGwBridge.bridgeName); err != nil {
if err := addIPv4DropForwardingRules(exGwBridge.bridgeName); err != nil {
return fmt.Errorf("failed to add forwarding block rules for bridge %s: err %v", exGwBridge.bridgeName, err)
}
} else {
if err := delExternalBridgeDropForwardingRules(exGwBridge.bridgeName); err != nil {
if err := delIPv4DropForwardingRules(exGwBridge.bridgeName); err != nil {
return fmt.Errorf("failed to delete forwarding block rules for bridge %s: err %v", exGwBridge.bridgeName, err)
}
}
Expand Down
16 changes: 12 additions & 4 deletions go-controller/pkg/node/gateway_shared_intf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1758,12 +1758,15 @@ func newSharedGateway(nodeName string, subnets []*net.IPNet, gwNextHops []net.IP
if err != nil {
return err
}

// There is no need to add/remove the drop rules for IPv6
// since there is already one configured in configureGlobalForwarding
if config.Gateway.DisableForwarding {
if err := initExternalBridgeDropForwardingRules(exGwBridge.bridgeName); err != nil {
if err := addIPv4DropForwardingRules(exGwBridge.bridgeName); err != nil {
return fmt.Errorf("failed to add forwarding block rules for bridge %s: err %v", exGwBridge.bridgeName, err)
}
} else {
if err := delExternalBridgeDropForwardingRules(exGwBridge.bridgeName); err != nil {
if err := delIPv4DropForwardingRules(exGwBridge.bridgeName); err != nil {
return fmt.Errorf("failed to delete forwarding block rules for bridge %s: err %v", exGwBridge.bridgeName, err)
}
}
Expand Down Expand Up @@ -1874,18 +1877,23 @@ func newNodePortWatcher(gwBridge *bridgeConfiguration, ofm *openflowManager,
subnets = append(subnets, subnet.CIDR)
}
subnets = append(subnets, config.Kubernetes.ServiceCIDRs...)

if config.Gateway.DisableForwarding {
if err := initExternalBridgeServiceForwardingRules(subnets); err != nil {
return nil, fmt.Errorf("failed to add forwarding rules for bridge %s: err %v", gwBridge.bridgeName, err)
}
if err := initExternalBridgeDropForwardingRules(gwBridge.bridgeName); err != nil {
// There is no need to add the drop rules for IPv6
// since there is already one configured in configureGlobalForwarding
if err := addIPv4DropForwardingRules(gwBridge.bridgeName); err != nil {
return nil, fmt.Errorf("failed to add forwarding rules for bridge %s: err %v", gwBridge.bridgeName, err)
}
} else {
if err := delExternalBridgeServiceForwardingRules(subnets); err != nil {
return nil, fmt.Errorf("failed to delete forwarding rules for bridge %s: err %v", gwBridge.bridgeName, err)
}
if err := delExternalBridgeDropForwardingRules(gwBridge.bridgeName); err != nil {
// There is no need to remove the drop rules for IPv6
// since there is already one configured in configureGlobalForwarding
if err := delIPv4DropForwardingRules(gwBridge.bridgeName); err != nil {
return nil, fmt.Errorf("failed to delete forwarding rules for bridge %s: err %v", gwBridge.bridgeName, err)
}
}
Expand Down

0 comments on commit 6c4d259

Please sign in to comment.