11package dataplane
22
33import (
4+ "errors"
5+ "fmt"
6+ "strconv"
7+ "strings"
8+
9+ "github.com/Azure/azure-container-networking/common"
10+ "github.com/Azure/azure-container-networking/npm/metrics"
411 "github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
512 "github.com/Azure/azure-container-networking/npm/util"
613 npmerrors "github.com/Azure/azure-container-networking/npm/util/errors"
14+
15+ "github.com/zcalusic/sysinfo"
16+ "k8s.io/klog"
717)
818
19+ const detectingErrMsg = "failed to detect iptables version. failed to find KUBE chains in iptables-legacy-save and iptables-nft-save and failed to get kernel version. NPM will crash to retry"
20+
21+ var errDetectingIptablesVersion = errors .New (detectingErrMsg )
22+
923func (dp * DataPlane ) getEndpointsToApplyPolicies (_ []* policies.NPMNetworkPolicy ) (map [string ]string , error ) {
1024 // NOOP in Linux
1125 return nil , nil
@@ -21,7 +35,9 @@ func (dp *DataPlane) updatePod(pod *updateNPMPod) error {
2135}
2236
2337func (dp * DataPlane ) bootupDataPlane () error {
24- util .DetectIptablesVersion (dp .ioShim )
38+ if err := detectIptablesVersion (dp .ioShim ); err != nil {
39+ return npmerrors .ErrorWrapper (npmerrors .BootupDataplane , false , "failed to detect iptables version" , err )
40+ }
2541
2642 // It is important to keep order to clean-up ACLs before ipsets. Otherwise we won't be able to delete ipsets referenced by ACLs
2743 if err := dp .policyMgr .Bootup (nil ); err != nil {
@@ -37,3 +53,81 @@ func (dp *DataPlane) refreshPodEndpoints() error {
3753 // NOOP in Linux
3854 return nil
3955}
56+
57+ // detectIptablesVersion sets the global iptables variable to nft if detected or legacy if detected.
58+ // NPM will crash if it fails to detect either.
59+ // This global variable is referenced in all iptables related functions.
60+ func detectIptablesVersion (ioShim * common.IOShim ) error {
61+ klog .Info ("first attempt detecting iptables version. running: iptables-nft-save -t mangle" )
62+ cmd := ioShim .Exec .Command (util .IptablesSaveNft , "-t" , "mangle" )
63+ output , err := cmd .CombinedOutput ()
64+ if err == nil && strings .Contains (string (output ), "KUBE-IPTABLES-HINT" ) || strings .Contains (string (output ), "KUBE-KUBELET-CANARY" ) {
65+ msg := "detected iptables version on first attempt. found KUBE chains in nft tables. NPM will use iptables-nft"
66+ klog .Info (msg )
67+ metrics .SendLog (util .DaemonDataplaneID , msg , metrics .DonotPrint )
68+ util .Iptables = util .IptablesNft
69+ util .IptablesSave = util .IptablesSaveNft
70+ util .IptablesRestore = util .IptablesRestoreNft
71+ return nil
72+ }
73+
74+ if err != nil {
75+ msg := fmt .Sprintf ("failed to detect iptables version on first attempt. error running iptables-nft-save. will try detecting using iptables-legacy-save. err: %w" , err )
76+ klog .Info (msg )
77+ metrics .SendErrorLogAndMetric (util .DaemonDataplaneID , msg )
78+ }
79+
80+ klog .Info ("second attempt detecting iptables version. running: iptables-legacy-save -t mangle" )
81+ lCmd := ioShim .Exec .Command (util .IptablesSaveLegacy , "-t" , "mangle" )
82+ loutput , err := lCmd .CombinedOutput ()
83+ if err == nil && strings .Contains (string (loutput ), "KUBE-IPTABLES-HINT" ) || strings .Contains (string (loutput ), "KUBE-KUBELET-CANARY" ) {
84+ msg := "detected iptables version on second attempt. found KUBE chains in legacy tables. NPM will use iptables-legacy"
85+ klog .Info (msg )
86+ metrics .SendLog (util .DaemonDataplaneID , msg , metrics .DonotPrint )
87+ util .Iptables = util .IptablesLegacy
88+ util .IptablesSave = util .IptablesSaveLegacy
89+ util .IptablesRestore = util .IptablesRestoreLegacy
90+ return nil
91+ }
92+
93+ if err != nil {
94+ msg := fmt .Sprintf ("failed to detect iptables version on second attempt. error running iptables-legacy-save. will try detecting using kernel version. err: %w" , err )
95+ klog .Info (msg )
96+ metrics .SendErrorLogAndMetric (util .DaemonDataplaneID , msg )
97+ }
98+
99+ klog .Info ("third attempt detecting iptables version. getting kernel version" )
100+ var si sysinfo.SysInfo
101+ si .GetSysInfo ()
102+ kernelVersion := strings .Split (si .Kernel .Release , "." )
103+ if kernelVersion [0 ] == "" {
104+ msg := fmt .Sprintf ("failed to detect iptables version on third attempt. error getting kernel version. err: %w" , err )
105+ klog .Info (msg )
106+ metrics .SendErrorLogAndMetric (util .DaemonDataplaneID , msg )
107+ return errDetectingIptablesVersion
108+ }
109+
110+ majorVersion , err := strconv .Atoi (kernelVersion [0 ])
111+ if err != nil {
112+ msg := fmt .Sprintf ("failed to detect iptables version on third attempt. error converting kernel version to int. err: %w" , err )
113+ klog .Info (msg )
114+ metrics .SendErrorLogAndMetric (util .DaemonDataplaneID , msg )
115+ return errDetectingIptablesVersion
116+ }
117+
118+ if majorVersion >= 5 {
119+ msg := "detected iptables version on third attempt. found kernel version >= 5. NPM will use iptables-nft"
120+ klog .Info (msg )
121+ metrics .SendLog (util .DaemonDataplaneID , msg , metrics .DonotPrint )
122+ util .Iptables = util .IptablesNft
123+ util .IptablesSave = util .IptablesSaveNft
124+ util .IptablesRestore = util .IptablesRestoreNft
125+ return nil
126+ }
127+
128+ msg := "detected iptables version on third attempt. found kernel version < 5. NPM will use iptables-legacy"
129+ klog .Info (msg )
130+ metrics .SendLog (util .DaemonDataplaneID , msg , metrics .DonotPrint )
131+
132+ return nil
133+ }
0 commit comments