@@ -37,6 +37,7 @@ import (
3737 "github.com/containernetworking/cni/pkg/types"
3838 current "github.com/containernetworking/cni/pkg/types/100"
3939 "github.com/containernetworking/cni/pkg/version"
40+ "github.com/containernetworking/plugins/pkg/utils"
4041 bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
4142)
4243
@@ -46,6 +47,12 @@ type PortMapper interface {
4647 unforwardPorts (config * PortMapConf ) error
4748}
4849
50+ // These are vars rather than consts so we can "&" them
51+ var (
52+ iptablesBackend = "iptables"
53+ nftablesBackend = "nftables"
54+ )
55+
4956// PortMapEntry corresponds to a single entry in the port_mappings argument,
5057// see CONVENTIONS.md
5158type PortMapEntry struct {
@@ -61,6 +68,7 @@ type PortMapConf struct {
6168 mapper PortMapper
6269
6370 // Generic config
71+ Backend * string `json:"backend,omitempty"`
6472 SNAT * bool `json:"snat,omitempty"`
6573 ConditionsV4 * []string `json:"conditionsV4"`
6674 ConditionsV6 * []string `json:"conditionsV6"`
@@ -240,6 +248,21 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, *current.Result, er
240248 return nil , nil , fmt .Errorf ("MasqMarkBit must be between 0 and 31" )
241249 }
242250
251+ err := ensureBackend (& conf )
252+ if err != nil {
253+ return nil , nil , err
254+ }
255+ switch * conf .Backend {
256+ case iptablesBackend :
257+ conf .mapper = & portMapperIPTables {}
258+
259+ case nftablesBackend :
260+ conf .mapper = & portMapperNFTables {}
261+
262+ default :
263+ return nil , nil , fmt .Errorf ("unrecognized backend %q" , * conf .Backend )
264+ }
265+
243266 // Reject invalid port numbers
244267 for _ , pm := range conf .RuntimeConfig .PortMaps {
245268 if pm .ContainerPort <= 0 {
@@ -279,3 +302,58 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, *current.Result, er
279302
280303 return & conf , result , nil
281304}
305+
306+ // ensureBackend validates and/or sets conf.Backend
307+ func ensureBackend (conf * PortMapConf ) error {
308+ backendConfig := make (map [string ][]string )
309+
310+ if conf .ExternalSetMarkChain != nil {
311+ backendConfig [iptablesBackend ] = append (backendConfig [iptablesBackend ], "externalSetMarkChain" )
312+ }
313+ if conditionsBackend := detectBackendOfConditions (conf .ConditionsV4 ); conditionsBackend != "" {
314+ backendConfig [conditionsBackend ] = append (backendConfig [conditionsBackend ], "conditionsV4" )
315+ }
316+ if conditionsBackend := detectBackendOfConditions (conf .ConditionsV6 ); conditionsBackend != "" {
317+ backendConfig [conditionsBackend ] = append (backendConfig [conditionsBackend ], "conditionsV6" )
318+ }
319+
320+ // If backend wasn't requested explicitly, default to iptables, unless it is not
321+ // available (and nftables is). FIXME: flip this default at some point.
322+ if conf .Backend == nil {
323+ if ! utils .SupportsIPTables () && utils .SupportsNFTables () {
324+ conf .Backend = & nftablesBackend
325+ } else {
326+ conf .Backend = & iptablesBackend
327+ }
328+ }
329+
330+ // Make sure we dont have config for the wrong backend
331+ var wrongBackend string
332+ if * conf .Backend == iptablesBackend {
333+ wrongBackend = nftablesBackend
334+ } else {
335+ wrongBackend = iptablesBackend
336+ }
337+ if len (backendConfig [wrongBackend ]) > 0 {
338+ return fmt .Errorf ("%s backend was requested but configuration contains %s-specific options %v" , * conf .Backend , wrongBackend , backendConfig [wrongBackend ])
339+ }
340+
341+ // OK
342+ return nil
343+ }
344+
345+ // detectBackendOfConditions returns "iptables" if conditions contains iptables
346+ // conditions, "nftables" if it contains nftables conditions, and "" if it is empty.
347+ func detectBackendOfConditions (conditions * []string ) string {
348+ if conditions == nil || len (* conditions ) == 0 || (* conditions )[0 ] == "" {
349+ return ""
350+ }
351+
352+ // The first token of any iptables condition would start with a hyphen (e.g. "-d",
353+ // "--sport", "-m"). No nftables condition would start that way. (An nftables
354+ // condition might include a negative number, but not as the first token.)
355+ if (* conditions )[0 ][0 ] == '-' {
356+ return iptablesBackend
357+ }
358+ return nftablesBackend
359+ }
0 commit comments