@@ -39,30 +39,59 @@ func (service *HTTPRestService) programSNATRules(req *cns.CreateNetworkContainer
3939
4040 chainExist , err := ipt .ChainExists (iptables .Nat , SWIFT )
4141 if err != nil {
42- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT chain: %v" , err )
42+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT-POSTROUTING chain: %v" , err )
4343 }
4444 if ! chainExist { // create and append chain if it doesn't exist
4545 logger .Printf ("[Azure CNS] Creating SWIFT Chain ..." )
4646 err = ipt .NewChain (iptables .Nat , SWIFT )
4747 if err != nil {
48- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to create SWIFT chain : " + err .Error ()
49- }
50- logger .Printf ("[Azure CNS] Append SWIFT Chain to POSTROUTING ..." )
51- err = ipt .Append (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
52- if err != nil {
53- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append SWIFT chain : " + err .Error ()
48+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to create SWIFT-POSTROUTING chain : " + err .Error ()
5449 }
5550 }
5651
57- postroutingToSwiftJumpexist , err := ipt .Exists (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
52+ // reconcile jump to SWIFT-POSTROUTING chain
53+ rules , err := ipt .List (iptables .Nat , iptables .Postrouting )
5854 if err != nil {
59- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of POSTROUTING to SWIFT chain jump: %v" , err )
55+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check rules in postrouting chain of nat table: %v" , err )
56+ }
57+ swiftRuleIndex := len (rules ) // append if neither jump rule from POSTROUTING is found
58+ // one time migration from old SWIFT chain
59+ // previously, CNI may have a jump to the SWIFT chain-- our jump to SWIFT-POSTROUTING needs to happen first
60+ for index , rule := range rules {
61+ if rule == "-A POSTROUTING -j SWIFT" {
62+ // jump to SWIFT comes before jump to SWIFT-POSTROUTING, so potential reordering required
63+ swiftRuleIndex = index
64+ break
65+ }
66+ if rule == "-A POSTROUTING -j SWIFT-POSTROUTING" {
67+ // jump to SWIFT-POSTROUTING comes before jump to SWIFT, which requires no further action
68+ swiftRuleIndex = - 1
69+ break
70+ }
6071 }
61- if ! postroutingToSwiftJumpexist {
62- logger .Printf ("[Azure CNS] Append SWIFT Chain to POSTROUTING ..." )
63- err = ipt .Append (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
72+ if swiftRuleIndex != - 1 {
73+ // jump SWIFT rule exists, insert SWIFT-POSTROUTING rule at the same position so it ends up running first
74+ // first, remove any existing SWIFT-POSTROUTING rules to avoid duplicates
75+ swiftPostroutingExists , err := ipt .Exists (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
76+ if err != nil {
77+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of SWIFT-POSTROUTING rule: %v" , err )
78+ }
79+ if swiftPostroutingExists {
80+ err = ipt .Delete (iptables .Nat , iptables .Postrouting , "-j" , SWIFT )
81+ if err != nil {
82+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to delete existing SWIFT-POSTROUTING rule : " + err .Error ()
83+ }
84+ }
85+
86+ // slice index is 0-based, iptables insert is 1-based, but list also gives us the -P POSTROUTING ACCEPT
87+ // as the first rule so swiftRuleIndex gives us the correct 1-indexed iptables position.
88+ // Example:
89+ // -P POSTROUTING ACCEPT is at swiftRuleIndex 0
90+ // -A POSTROUTING -j SWIFT is at swiftRuleIndex 1, and iptables index 1
91+ logger .Printf ("[Azure CNS] Inserting SWIFT-POSTROUTING Chain at iptables position %d" , swiftRuleIndex )
92+ err = ipt .Insert (iptables .Nat , iptables .Postrouting , swiftRuleIndex , "-j" , SWIFT )
6493 if err != nil {
65- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append SWIFT chain : " + err .Error ()
94+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert SWIFT-POSTROUTING chain : " + err .Error ()
6695 }
6796 }
6897
@@ -71,39 +100,47 @@ func (service *HTTPRestService) programSNATRules(req *cns.CreateNetworkContainer
71100 // put the ip address in standard cidr form (where we zero out the parts that are not relevant)
72101 _ , podSubnet , _ := net .ParseCIDR (v .IPAddress + "/" + fmt .Sprintf ("%d" , req .IPConfiguration .IPSubnet .PrefixLength ))
73102
74- snatUDPRuleExists , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
75- if err != nil {
76- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT UDP rule : %v" , err )
103+ // define all rules we want in the chain
104+ rules := [][]string {
105+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ()},
106+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ()},
107+ {"-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP },
77108 }
78- if ! snatUDPRuleExists {
79- logger .Printf ("[Azure CNS] Inserting pod SNAT UDP rule ..." )
80- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .UDP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
109+
110+ // check if all rules exist
111+ allRulesExist := true
112+ for _ , rule := range rules {
113+ exists , err := ipt .Exists (iptables .Nat , SWIFT , rule ... )
81114 if err != nil {
82- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT UDP rule : " + err .Error ()
115+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of rule: %v" , err )
116+ }
117+ if ! exists {
118+ allRulesExist = false
119+ break
83120 }
84121 }
85122
86- snatPodTCPRuleExists , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
123+ // get current rule count in SWIFT-POSTROUTING chain
124+ currentRules , err := ipt .List (iptables .Nat , SWIFT )
87125 if err != nil {
88- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT TCP rule : %v" , err )
126+ return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to list rules in SWIFT-POSTROUTING chain : %v" , err )
89127 }
90- if ! snatPodTCPRuleExists {
91- logger .Printf ("[Azure CNS] Inserting pod SNAT TCP rule ..." )
92- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureDNS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .DNSPort ), "-j" , iptables .Snat , "--to" , ncPrimaryIP .String ())
128+
129+ // if rule count doesn't match or not all rules exist, reconcile
130+ // add one because there is always a singular starting rule in the chain, in addition to the ones we add
131+ if len (currentRules ) != len (rules )+ 1 || ! allRulesExist {
132+ logger .Printf ("[Azure CNS] Reconciling SWIFT-POSTROUTING chain rules" )
133+
134+ err = ipt .ClearChain (iptables .Nat , SWIFT )
93135 if err != nil {
94- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT TCP rule : " + err .Error ()
136+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to flush SWIFT-POSTROUTING chain : " + err .Error ()
95137 }
96- }
97138
98- snatIMDSRuleexist , err := ipt .Exists (iptables .Nat , SWIFT , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP )
99- if err != nil {
100- return types .UnexpectedError , fmt .Sprintf ("[Azure CNS] Error. Failed to check for existence of pod SNAT IMDS rule : %v" , err )
101- }
102- if ! snatIMDSRuleexist {
103- logger .Printf ("[Azure CNS] Inserting pod SNAT IMDS rule ..." )
104- err = ipt .Insert (iptables .Nat , SWIFT , 1 , "-m" , "addrtype" , "!" , "--dst-type" , "local" , "-s" , podSubnet .String (), "-d" , networkutils .AzureIMDS , "-p" , iptables .TCP , "--dport" , strconv .Itoa (iptables .HTTPPort ), "-j" , iptables .Snat , "--to" , req .HostPrimaryIP )
105- if err != nil {
106- return types .FailedToRunIPTableCmd , "[Azure CNS] failed to insert pod SNAT IMDS rule : " + err .Error ()
139+ for _ , rule := range rules {
140+ err = ipt .Append (iptables .Nat , SWIFT , rule ... )
141+ if err != nil {
142+ return types .FailedToRunIPTableCmd , "[Azure CNS] failed to append rule to SWIFT-POSTROUTING chain : " + err .Error ()
143+ }
107144 }
108145 }
109146
0 commit comments