Adding node interface, SNAT and OVN Node switch port
[ovn4nfv-k8s-plugin.git] / internal / pkg / network / iptables.go
1 package network
2
3 import (
4         "fmt"
5         "strings"
6
7         logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
8
9         "github.com/coreos/go-iptables/iptables"
10 )
11
12 var log = logf.Log.WithName("iptables")
13
14 type IPTables interface {
15         AppendUnique(table string, chain string, rulespec ...string) error
16         Delete(table string, chain string, rulespec ...string) error
17         Exists(table string, chain string, rulespec ...string) (bool, error)
18 }
19
20 type IPTablesRule struct {
21         table    string
22         chain    string
23         rulespec []string
24 }
25
26 func MasqRules(ifname string) []IPTablesRule {
27         return []IPTablesRule{
28                 // This rule makes sure ifname is SNAT
29                 {"nat", "POSTROUTING", []string{"-o", ifname, "-j", "MASQUERADE"}},
30         }
31 }
32
33 func ForwardRules(ovnNetwork string) []IPTablesRule {
34         return []IPTablesRule{
35                 // These rules allow traffic to be forwarded if it is to or from the ovn network range.
36                 {"filter", "FORWARD", []string{"-s", ovnNetwork, "-j", "ACCEPT"}},
37                 {"filter", "FORWARD", []string{"-d", ovnNetwork, "-j", "ACCEPT"}},
38         }
39 }
40
41 func ipTablesRulesExist(ipt IPTables, rules []IPTablesRule) (bool, error) {
42         for _, rule := range rules {
43                 exists, err := ipt.Exists(rule.table, rule.chain, rule.rulespec...)
44                 if err != nil {
45                         // this shouldn't ever happen
46                         return false, fmt.Errorf("failed to check rule existence: %v", err)
47                 }
48                 if !exists {
49                         return false, nil
50                 }
51         }
52
53         return true, nil
54 }
55
56 func SetupAndEnsureIPTables(rules []IPTablesRule) error {
57         ipt, err := iptables.New()
58         if err != nil {
59                 // if we can't find iptables, give up and return
60                 log.Error(err, "Failed to setup IPTables. iptables binary was not found")
61                 return err
62         }
63
64         // Ensure that all the iptables rules exist every 5 seconds
65         if err := ensureIPTables(ipt, rules); err != nil {
66                 log.Error(err, "Failed to ensure iptables rules")
67                 return err
68         }
69
70         return nil
71
72 }
73
74 // DeleteIPTables delete specified iptables rules
75 func DeleteIPTables(rules []IPTablesRule) error {
76         ipt, err := iptables.New()
77         if err != nil {
78                 // if we can't find iptables, give up and return
79                 log.Error(err, "Failed to setup IPTables. iptables binary was not found")
80                 return err
81         }
82         teardownIPTables(ipt, rules)
83         return nil
84 }
85
86 func ensureIPTables(ipt IPTables, rules []IPTablesRule) error {
87         exists, err := ipTablesRulesExist(ipt, rules)
88         if err != nil {
89                 return fmt.Errorf("Error checking rule existence: %v", err)
90         }
91         if exists {
92                 // if all the rules already exist, no need to do anything
93                 return nil
94         }
95         // Otherwise, teardown all the rules and set them up again
96         // We do this because the order of the rules is important
97         log.Info("Some iptables rules are missing; deleting and recreating rules")
98         teardownIPTables(ipt, rules)
99         if err = setupIPTables(ipt, rules); err != nil {
100                 return fmt.Errorf("Error setting up rules: %v", err)
101         }
102         return nil
103 }
104
105 func setupIPTables(ipt IPTables, rules []IPTablesRule) error {
106         for _, rule := range rules {
107                 log.Info("Adding iptables rule: ", "rule", strings.Join(rule.rulespec, " "))
108                 err := ipt.AppendUnique(rule.table, rule.chain, rule.rulespec...)
109                 if err != nil {
110                         return fmt.Errorf("failed to insert IPTables rule: %v", err)
111                 }
112         }
113
114         return nil
115 }
116
117 func teardownIPTables(ipt IPTables, rules []IPTablesRule) {
118         for _, rule := range rules {
119                 log.Info("Deleting iptables rule: ", "rule", strings.Join(rule.rulespec, " "))
120                 // We ignore errors here because if there's an error it's almost certainly because the rule
121                 // doesn't exist, which is fine (we don't need to delete rules that don't exist)
122                 ipt.Delete(rule.table, rule.chain, rule.rulespec...)
123         }
124 }