Commit 1e7db4a1 authored by Tim Hockin's avatar Tim Hockin Committed by Matt Dupre

Implement proper cleanup in iptables proxy

parent 107c5f78
...@@ -198,24 +198,29 @@ func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod ...@@ -198,24 +198,29 @@ func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod
// CleanupLeftovers removes all iptables rules and chains created by the Proxier // CleanupLeftovers removes all iptables rules and chains created by the Proxier
// It returns true if an error was encountered. Errors are logged. // It returns true if an error was encountered. Errors are logged.
func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) { func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) {
//TODO: actually tear down all rules and chains. // Unlink the services chain.
args := []string{ args := []string{
"-m", "comment", "--comment", "kubernetes service portals", "-m", "comment", "--comment", "kubernetes service portals",
"-j", string(kubeServicesChain), "-j", string(kubeServicesChain),
} }
if err := ipt.DeleteRule(utiliptables.TableNAT, utiliptables.ChainOutput, args...); err != nil { tableChainsWithJumpServices := []struct {
if !utiliptables.IsNotFoundError(err) { table utiliptables.Table
glog.Errorf("Error removing pure-iptables proxy rule: %v", err) chain utiliptables.Chain
encounteredError = true }{
} {utiliptables.TableFilter, utiliptables.ChainOutput},
{utiliptables.TableNAT, utiliptables.ChainOutput},
{utiliptables.TableNAT, utiliptables.ChainPrerouting},
} }
if err := ipt.DeleteRule(utiliptables.TableNAT, utiliptables.ChainPrerouting, args...); err != nil { for _, tc := range tableChainsWithJumpServices {
if !utiliptables.IsNotFoundError(err) { if err := ipt.DeleteRule(tc.table, tc.chain, args...); err != nil {
glog.Errorf("Error removing pure-iptables proxy rule: %v", err) if !utiliptables.IsNotFoundError(err) {
encounteredError = true glog.Errorf("Error removing pure-iptables proxy rule: %v", err)
encounteredError = true
}
} }
} }
// Unlink the postrouting chain.
args = []string{ args = []string{
"-m", "comment", "--comment", "kubernetes postrouting rules", "-m", "comment", "--comment", "kubernetes postrouting rules",
"-j", string(kubePostroutingChain), "-j", string(kubePostroutingChain),
...@@ -227,23 +232,51 @@ func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) { ...@@ -227,23 +232,51 @@ func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) {
} }
} }
// flush and delete chains. // Flush and remove all of our chains.
chains := []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, kubeMarkMasqChain} if iptablesSaveRaw, err := ipt.Save(utiliptables.TableNAT); err != nil {
for _, c := range chains { glog.Errorf("Failed to execute iptables-save for %s: %v", utiliptables.TableNAT, err)
// flush chain, then if sucessful delete, delete will fail if flush fails. encounteredError = true
if err := ipt.FlushChain(utiliptables.TableNAT, c); err != nil { } else {
if !utiliptables.IsNotFoundError(err) { existingNATChains := getChainLines(utiliptables.TableNAT, iptablesSaveRaw)
glog.Errorf("Error flushing pure-iptables proxy chain: %v", err) natChains := bytes.NewBuffer(nil)
encounteredError = true natRules := bytes.NewBuffer(nil)
writeLine(natChains, "*nat")
// Start with chains we know we need to remove.
for _, chain := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, kubeMarkMasqChain} {
if _, found := existingNATChains[chain]; found {
chainString := string(chain)
writeLine(natChains, existingNATChains[chain]) // flush
writeLine(natRules, "-X", chainString) // delete
} }
} else { }
if err = ipt.DeleteChain(utiliptables.TableNAT, c); err != nil { // Hunt for service and endpoint chains.
if !utiliptables.IsNotFoundError(err) { for chain := range existingNATChains {
glog.Errorf("Error deleting pure-iptables proxy chain: %v", err) chainString := string(chain)
encounteredError = true if strings.HasPrefix(chainString, "KUBE-SVC-") || strings.HasPrefix(chainString, "KUBE-SEP-") {
} writeLine(natChains, existingNATChains[chain]) // flush
writeLine(natRules, "-X", chainString) // delete
} }
} }
writeLine(natRules, "COMMIT")
natLines := append(natChains.Bytes(), natRules.Bytes()...)
// Write it.
err = ipt.Restore(utiliptables.TableNAT, natLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters)
if err != nil {
glog.Errorf("Failed to execute iptables-restore for %s: %v", utiliptables.TableNAT, err)
encounteredError = true
}
}
{
filterBuf := bytes.NewBuffer(nil)
writeLine(filterBuf, "*filter")
writeLine(filterBuf, fmt.Sprintf(":%s - [0:0]", kubeServicesChain))
writeLine(filterBuf, fmt.Sprintf("-X %s", kubeServicesChain))
writeLine(filterBuf, "COMMIT")
// Write it.
if err := ipt.Restore(utiliptables.TableFilter, filterBuf.Bytes(), utiliptables.NoFlushTables, utiliptables.RestoreCounters); err != nil {
glog.Errorf("Failed to execute iptables-restore for %s: %v", utiliptables.TableFilter, err)
encounteredError = true
}
} }
// Clean up the older SNAT rule which was directly in POSTROUTING. // Clean up the older SNAT rule which was directly in POSTROUTING.
...@@ -554,7 +587,7 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -554,7 +587,7 @@ func (proxier *Proxier) syncProxyRules() {
existingFilterChains := make(map[utiliptables.Chain]string) existingFilterChains := make(map[utiliptables.Chain]string)
iptablesSaveRaw, err := proxier.iptables.Save(utiliptables.TableFilter) iptablesSaveRaw, err := proxier.iptables.Save(utiliptables.TableFilter)
if err != nil { // if we failed to get any rules if err != nil { // if we failed to get any rules
glog.Errorf("Failed to execute iptables-save, syncing all rules. %s", err.Error()) glog.Errorf("Failed to execute iptables-save, syncing all rules: %v", err)
} else { // otherwise parse the output } else { // otherwise parse the output
existingFilterChains = getChainLines(utiliptables.TableFilter, iptablesSaveRaw) existingFilterChains = getChainLines(utiliptables.TableFilter, iptablesSaveRaw)
} }
...@@ -562,7 +595,7 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -562,7 +595,7 @@ func (proxier *Proxier) syncProxyRules() {
existingNATChains := make(map[utiliptables.Chain]string) existingNATChains := make(map[utiliptables.Chain]string)
iptablesSaveRaw, err = proxier.iptables.Save(utiliptables.TableNAT) iptablesSaveRaw, err = proxier.iptables.Save(utiliptables.TableNAT)
if err != nil { // if we failed to get any rules if err != nil { // if we failed to get any rules
glog.Errorf("Failed to execute iptables-save, syncing all rules. %s", err.Error()) glog.Errorf("Failed to execute iptables-save, syncing all rules: %v", err)
} else { // otherwise parse the output } else { // otherwise parse the output
existingNATChains = getChainLines(utiliptables.TableNAT, iptablesSaveRaw) existingNATChains = getChainLines(utiliptables.TableNAT, iptablesSaveRaw)
} }
...@@ -874,10 +907,10 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -874,10 +907,10 @@ func (proxier *Proxier) syncProxyRules() {
natLines := append(natChains.Bytes(), natRules.Bytes()...) natLines := append(natChains.Bytes(), natRules.Bytes()...)
lines := append(filterLines, natLines...) lines := append(filterLines, natLines...)
glog.V(3).Infof("Syncing iptables rules: %s", lines) glog.V(3).Infof("Restoring iptables rules: %s", lines)
err = proxier.iptables.RestoreAll(lines, utiliptables.NoFlushTables, utiliptables.RestoreCounters) err = proxier.iptables.RestoreAll(lines, utiliptables.NoFlushTables, utiliptables.RestoreCounters)
if err != nil { if err != nil {
glog.Errorf("Failed to sync iptables rules: %v", err) glog.Errorf("Failed to execute iptables-restore: %v", err)
// Revert new local ports. // Revert new local ports.
for k, v := range newLocalPorts { for k, v := range newLocalPorts {
glog.Errorf("Closing local port %s", k.String()) glog.Errorf("Closing local port %s", k.String())
......
...@@ -296,6 +296,7 @@ func (runner *runner) Save(table Table) ([]byte, error) { ...@@ -296,6 +296,7 @@ func (runner *runner) Save(table Table) ([]byte, error) {
// run and return // run and return
args := []string{"-t", string(table)} args := []string{"-t", string(table)}
glog.V(4).Infof("running iptables-save %v", args)
return runner.exec.Command(cmdIptablesSave, args...).CombinedOutput() return runner.exec.Command(cmdIptablesSave, args...).CombinedOutput()
} }
...@@ -305,6 +306,7 @@ func (runner *runner) SaveAll() ([]byte, error) { ...@@ -305,6 +306,7 @@ func (runner *runner) SaveAll() ([]byte, error) {
defer runner.mu.Unlock() defer runner.mu.Unlock()
// run and return // run and return
glog.V(4).Infof("running iptables-save")
return runner.exec.Command(cmdIptablesSave, []string{}...).CombinedOutput() return runner.exec.Command(cmdIptablesSave, []string{}...).CombinedOutput()
} }
...@@ -354,6 +356,7 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla ...@@ -354,6 +356,7 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla
return err return err
} }
// run the command and return the output or an error including the output and error // run the command and return the output or an error including the output and error
glog.V(4).Infof("running iptables-restore %v", args)
b, err := runner.exec.Command(cmdIptablesRestore, args...).CombinedOutput() b, err := runner.exec.Command(cmdIptablesRestore, args...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("%v (%s)", err, b) return fmt.Errorf("%v (%s)", err, b)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment