package plugin
import (
"fmt"
"sync"
"time"
"github.com/golang/glog"
utildbus "k8s.io/kubernetes/pkg/util/dbus"
kexec "k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/util/iptables"
utilwait "k8s.io/kubernetes/pkg/util/wait"
)
type FirewallRule struct {
table string
chain string
args []string
}
type NodeIPTables struct {
ipt iptables.Interface
clusterNetworkCIDR string
syncPeriod time.Duration
mu sync.Mutex // Protects concurrent access to syncIPTableRules()
}
func newNodeIPTables(clusterNetworkCIDR string, syncPeriod time.Duration) *NodeIPTables {
return &NodeIPTables{
ipt: iptables.New(kexec.New(), utildbus.New(), iptables.ProtocolIpv4),
clusterNetworkCIDR: clusterNetworkCIDR,
syncPeriod: syncPeriod,
}
}
func (n *NodeIPTables) Setup() error {
if err := n.syncIPTableRules(); err != nil {
return err
}
// If firewalld is running, reload will call this method
n.ipt.AddReloadFunc(func() {
if err := n.syncIPTableRules(); err != nil {
glog.Errorf("Reloading openshift iptables failed: %v", err)
}
})
go utilwait.Forever(n.syncLoop, 0)
return nil
}
// syncLoop periodically calls syncIPTableRules().
// This is expected to run as a go routine or as the main loop. It does not return.
func (n *NodeIPTables) syncLoop() {
t := time.NewTicker(n.syncPeriod)
defer t.Stop()
for {
<-t.C
glog.V(6).Infof("Periodic openshift iptables sync")
err := n.syncIPTableRules()
if err != nil {
glog.Errorf("Syncing openshift iptables failed: %v", err)
}
}
}
// syncIPTableRules syncs the cluster network cidr iptables rules.
// Called from SyncLoop() or firwalld reload()
func (n *NodeIPTables) syncIPTableRules() error {
n.mu.Lock()
defer n.mu.Unlock()
start := time.Now()
defer func() {
glog.V(4).Infof("syncIPTableRules took %v", time.Since(start))
}()
glog.V(3).Infof("Syncing openshift iptables rules")
rules := n.getStaticNodeIPTablesRules()
for _, rule := range rules {
_, err := n.ipt.EnsureRule(iptables.Prepend, iptables.Table(rule.table), iptables.Chain(rule.chain), rule.args...)
if err != nil {
return fmt.Errorf("Failed to ensure rule %v exists: %v", rule, err)
}
}
return nil
}
// Get openshift iptables rules
func (n *NodeIPTables) getStaticNodeIPTablesRules() []FirewallRule {
return []FirewallRule{
{"nat", "POSTROUTING", []string{"-s", n.clusterNetworkCIDR, "-j", "MASQUERADE"}},
{"filter", "INPUT", []string{"-p", "udp", "-m", "multiport", "--dports", VXLAN_PORT, "-m", "comment", "--comment", "001 vxlan incoming", "-j", "ACCEPT"}},
{"filter", "INPUT", []string{"-i", TUN, "-m", "comment", "--comment", "traffic from SDN", "-j", "ACCEPT"}},
{"filter", "INPUT", []string{"-i", "docker0", "-m", "comment", "--comment", "traffic from docker", "-j", "ACCEPT"}},
{"filter", "FORWARD", []string{"-d", n.clusterNetworkCIDR, "-j", "ACCEPT"}},
{"filter", "FORWARD", []string{"-s", n.clusterNetworkCIDR, "-j", "ACCEPT"}},
}
}