Hello community,

here is the log from the commit of package cni-plugins for openSUSE:Factory 
checked in at 2020-01-12 23:17:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/cni-plugins (Old)
 and      /work/SRC/openSUSE:Factory/.cni-plugins.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "cni-plugins"

Sun Jan 12 23:17:46 2020 rev:9 rq:762245 version:0.8.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/cni-plugins/cni-plugins.changes  2019-11-15 
22:32:41.144062548 +0100
+++ /work/SRC/openSUSE:Factory/.cni-plugins.new.6675/cni-plugins.changes        
2020-01-12 23:18:15.370680145 +0100
@@ -1,0 +2,12 @@
+Thu Jan  9 13:24:41 UTC 2020 - Sascha Grunert <[email protected]>
+
+- Update to version 0.8.4:
+  * add support for mips64le
+  * Add missing cniVersion in README example
+  * bump go-iptables module to v0.4.5
+  * iptables: add idempotent functions
+  * portmap doesn't fail if chain doesn't exist
+  * fix portmap port forward flakiness
+  * Add Bruce Ma and Piotr Skarmuk as owners
+
+-------------------------------------------------------------------

Old:
----
  cni-plugins-0.8.3.tar.xz

New:
----
  cni-plugins-0.8.4.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ cni-plugins.spec ++++++
--- /var/tmp/diff_new_pack.tiNr9u/_old  2020-01-12 23:18:16.150680433 +0100
+++ /var/tmp/diff_new_pack.tiNr9u/_new  2020-01-12 23:18:16.150680433 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package cni-plugins
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,12 +20,12 @@
 %define         cni_doc_dir  %{_docdir}/cni-plugins
 
 Name:           cni-plugins
-Version:        0.8.3
+Version:        0.8.4
 Release:        0
 Summary:        Container Network Interface plugins
 License:        Apache-2.0
 Group:          System/Management
-Url:            https://github.com/containernetworking/plugins
+URL:            https://github.com/containernetworking/plugins
 Source:         %{name}-%{version}.tar.xz
 BuildRequires:  go >= 1.11
 BuildRequires:  golang-packaging

++++++ _service ++++++
--- /var/tmp/diff_new_pack.tiNr9u/_old  2020-01-12 23:18:16.170680440 +0100
+++ /var/tmp/diff_new_pack.tiNr9u/_new  2020-01-12 23:18:16.170680440 +0100
@@ -4,8 +4,8 @@
     <param name="scm">git</param>
     <param name="filename">cni-plugins</param>
     <param name="exclude">.git</param>
-    <param name="versionformat">0.8.3</param>
-    <param name="revision">v0.8.3</param>
+    <param name="versionformat">0.8.4</param>
+    <param name="revision">v0.8.4</param>
     <param name="changesgenerate">enable</param>
   </service>
   <service name="recompress" mode="disabled">

++++++ cni-plugins-0.8.3.tar.xz -> cni-plugins-0.8.4.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/.travis.yml 
new/cni-plugins-0.8.4/.travis.yml
--- old/cni-plugins-0.8.3/.travis.yml   2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/.travis.yml   2020-01-08 17:26:13.000000000 +0100
@@ -18,6 +18,7 @@
   - TARGET=arm64
   - TARGET=ppc64le
   - TARGET=s390x
+  - TARGET=mips64le
 
 matrix:
   fast_finish: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/OWNERS.md 
new/cni-plugins-0.8.4/OWNERS.md
--- old/cni-plugins-0.8.3/OWNERS.md     2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/OWNERS.md     2020-01-08 17:26:13.000000000 +0100
@@ -1,8 +1,10 @@
 # Owners
 This is the official list of the CNI network plugins owners:
+- Bruce Ma <[email protected]> (@mars1024)
 - Bryan Boreham <[email protected]> (@bboreham)
 - Casey Callendrello <[email protected]> (@squeed)
 - Dan Williams <[email protected]> (@dcbw)
 - Gabe Rosenhouse <[email protected]> (@rosenhouse)
 - Matt Dupre <[email protected]> (@matthewdupre)
+- Piotr Skarmuk <[email protected]> (@jellonek)
 - Stefan Junker <[email protected]> (@steveeJ)
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/go.mod new/cni-plugins-0.8.4/go.mod
--- old/cni-plugins-0.8.3/go.mod        2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/go.mod        2020-01-08 17:26:13.000000000 +0100
@@ -8,7 +8,7 @@
        github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae
        github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44
        github.com/containernetworking/cni v0.7.1
-       github.com/coreos/go-iptables v0.4.2
+       github.com/coreos/go-iptables v0.4.5
        github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
        github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
        github.com/d2g/dhcp4client v1.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/go.sum new/cni-plugins-0.8.4/go.sum
--- old/cni-plugins-0.8.3/go.sum        2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/go.sum        2020-01-08 17:26:13.000000000 +0100
@@ -10,6 +10,10 @@
 github.com/containernetworking/cni v0.7.1/go.mod 
h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
 github.com/coreos/go-iptables v0.4.2 
h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
 github.com/coreos/go-iptables v0.4.2/go.mod 
h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.4.4 
h1:5oOUvU7Fk53Hn/rkdJ0zcYGCffotqXpyi4ADCkO1TJ8=
+github.com/coreos/go-iptables v0.4.4/go.mod 
h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.4.5 
h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
+github.com/coreos/go-iptables v0.4.5/go.mod 
h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 
h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod 
h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c 
h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/pkg/utils/iptables.go 
new/cni-plugins-0.8.4/pkg/utils/iptables.go
--- old/cni-plugins-0.8.3/pkg/utils/iptables.go 1970-01-01 01:00:00.000000000 
+0100
+++ new/cni-plugins-0.8.4/pkg/utils/iptables.go 2020-01-08 17:26:13.000000000 
+0100
@@ -0,0 +1,121 @@
+// Copyright 2017 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils
+
+import (
+       "errors"
+       "fmt"
+
+       "github.com/coreos/go-iptables/iptables"
+)
+
+const statusChainExists = 1
+
+// EnsureChain idempotently creates the iptables chain. It does not
+// return an error if the chain already exists.
+func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
+       if ipt == nil {
+               return errors.New("failed to ensure iptable chain: IPTables was 
nil")
+       }
+       exists, err := ChainExists(ipt, table, chain)
+       if err != nil {
+               return fmt.Errorf("failed to list iptables chains: %v", err)
+       }
+       if !exists {
+               err = ipt.NewChain(table, chain)
+               if err != nil {
+                       eerr, eok := err.(*iptables.Error)
+                       if eok && eerr.ExitStatus() != statusChainExists {
+                               return err
+                       }
+               }
+       }
+       return nil
+}
+
+// ChainExists checks whether an iptables chain exists.
+func ChainExists(ipt *iptables.IPTables, table, chain string) (bool, error) {
+       if ipt == nil {
+               return false, errors.New("failed to check iptable chain: 
IPTables was nil")
+       }
+       chains, err := ipt.ListChains(table)
+       if err != nil {
+               return false, err
+       }
+
+       for _, ch := range chains {
+               if ch == chain {
+                       return true, nil
+               }
+       }
+       return false, nil
+}
+
+// DeleteRule idempotently delete the iptables rule in the specified 
table/chain.
+// It does not return an error if the referring chain doesn't exist
+func DeleteRule(ipt *iptables.IPTables, table, chain string, rulespec 
...string) error {
+       if ipt == nil {
+               return errors.New("failed to ensure iptable chain: IPTables was 
nil")
+       }
+       if err := ipt.Delete(table, chain, rulespec...); err != nil {
+               eerr, eok := err.(*iptables.Error)
+               switch {
+               case eok && eerr.IsNotExist():
+                       // swallow here, the chain was already deleted
+                       return nil
+               case eok && eerr.ExitStatus() == 2:
+                       // swallow here, invalid command line parameter because 
the referring rule is missing
+                       return nil
+               default:
+                       return fmt.Errorf("Failed to delete referring rule %s 
%s: %v", table, chain, err)
+               }
+       }
+       return nil
+}
+
+// DeleteChain idempotently deletes the specified table/chain.
+// It does not return an errors if the chain does not exist
+func DeleteChain(ipt *iptables.IPTables, table, chain string) error {
+       if ipt == nil {
+               return errors.New("failed to ensure iptable chain: IPTables was 
nil")
+       }
+
+       err := ipt.DeleteChain(table, chain)
+       eerr, eok := err.(*iptables.Error)
+       switch {
+       case eok && eerr.IsNotExist():
+               // swallow here, the chain was already deleted
+               return nil
+       default:
+               return err
+       }
+}
+
+// ClearChain idempotently clear the iptables rules in the specified 
table/chain.
+// If the chain does not exist, a new one will be created
+func ClearChain(ipt *iptables.IPTables, table, chain string) error {
+       if ipt == nil {
+               return errors.New("failed to ensure iptable chain: IPTables was 
nil")
+       }
+       err := ipt.ClearChain(table, chain)
+       eerr, eok := err.(*iptables.Error)
+       switch {
+       case eok && eerr.IsNotExist():
+               // swallow here, the chain was already deleted
+               return EnsureChain(ipt, table, chain)
+       default:
+               return err
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/pkg/utils/iptables_test.go 
new/cni-plugins-0.8.4/pkg/utils/iptables_test.go
--- old/cni-plugins-0.8.3/pkg/utils/iptables_test.go    1970-01-01 
01:00:00.000000000 +0100
+++ new/cni-plugins-0.8.4/pkg/utils/iptables_test.go    2020-01-08 
17:26:13.000000000 +0100
@@ -0,0 +1,97 @@
+// Copyright 2017-2018 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils
+
+import (
+       "fmt"
+       "math/rand"
+       "runtime"
+
+       "github.com/containernetworking/plugins/pkg/ns"
+       "github.com/containernetworking/plugins/pkg/testutils"
+       "github.com/coreos/go-iptables/iptables"
+       . "github.com/onsi/ginkgo"
+       . "github.com/onsi/gomega"
+)
+
+const TABLE = "filter" // We'll monkey around here
+
+var _ = Describe("chain tests", func() {
+       var testChain string
+       var ipt *iptables.IPTables
+       var cleanup func()
+
+       BeforeEach(func() {
+
+               // Save a reference to the original namespace,
+               // Add a new NS
+               currNs, err := ns.GetCurrentNS()
+               Expect(err).NotTo(HaveOccurred())
+
+               testNs, err := testutils.NewNS()
+               Expect(err).NotTo(HaveOccurred())
+
+               testChain = fmt.Sprintf("cni-test-%d", rand.Intn(10000000))
+
+               ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv4)
+               Expect(err).NotTo(HaveOccurred())
+
+               runtime.LockOSThread()
+               err = testNs.Set()
+               Expect(err).NotTo(HaveOccurred())
+
+               cleanup = func() {
+                       if ipt == nil {
+                               return
+                       }
+                       ipt.ClearChain(TABLE, testChain)
+                       ipt.DeleteChain(TABLE, testChain)
+                       currNs.Set()
+               }
+
+       })
+
+       AfterEach(func() {
+               cleanup()
+       })
+
+       Describe("EnsureChain", func() {
+               It("creates chains idempotently", func() {
+                       err := EnsureChain(ipt, TABLE, testChain)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       // Create it again!
+                       err = EnsureChain(ipt, TABLE, testChain)
+                       Expect(err).NotTo(HaveOccurred())
+               })
+       })
+
+       Describe("DeleteChain", func() {
+               It("delete chains idempotently", func() {
+                       // Create chain
+                       err := EnsureChain(ipt, TABLE, testChain)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       // Delete chain
+                       err = DeleteChain(ipt, TABLE, testChain)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       // Delete it again!
+                       err = DeleteChain(ipt, TABLE, testChain)
+                       Expect(err).NotTo(HaveOccurred())
+               })
+       })
+
+})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/plugins/main/bridge/README.md 
new/cni-plugins-0.8.4/plugins/main/bridge/README.md
--- old/cni-plugins-0.8.3/plugins/main/bridge/README.md 2019-11-11 
14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/main/bridge/README.md 2020-01-08 
17:26:13.000000000 +0100
@@ -14,17 +14,18 @@
 ## Example configuration
 ```
 {
-       "name": "mynet",
-       "type": "bridge",
-       "bridge": "mynet0",
-       "isDefaultGateway": true,
-       "forceAddress": false,
-       "ipMasq": true,
-       "hairpinMode": true,
-       "ipam": {
-               "type": "host-local",
-               "subnet": "10.10.0.0/16"
-       }
+    "cniVersion": "0.3.1",
+    "name": "mynet",
+    "type": "bridge",
+    "bridge": "mynet0",
+    "isDefaultGateway": true,
+    "forceAddress": false,
+    "ipMasq": true,
+    "hairpinMode": true,
+    "ipam": {
+        "type": "host-local",
+        "subnet": "10.10.0.0/16"
+    }
 }
 ```
 
@@ -32,10 +33,10 @@
 ```
 {
     "cniVersion": "0.3.1",
-       "name": "mynet",
-       "type": "bridge",
-       "bridge": "mynet0",
-       "ipam": {}
+    "name": "mynet",
+    "type": "bridge",
+    "bridge": "mynet0",
+    "ipam": {}
 }
 ```
 
@@ -56,4 +57,4 @@
 
 *Note:* The VLAN parameter configures the VLAN tag on the host end of the veth 
and also enables the vlan_filtering feature on the bridge interface.
 
-*Note:* To configure uplink for L2 network you need to allow the vlan on the 
uplink interface by using the following command ``` bridge vlan add vid VLAN_ID 
dev DEV```.
\ No newline at end of file
+*Note:* To configure uplink for L2 network you need to allow the vlan on the 
uplink interface by using the following command ``` bridge vlan add vid VLAN_ID 
dev DEV```.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cni-plugins-0.8.3/plugins/meta/firewall/firewall_iptables_test.go 
new/cni-plugins-0.8.4/plugins/meta/firewall/firewall_iptables_test.go
--- old/cni-plugins-0.8.3/plugins/meta/firewall/firewall_iptables_test.go       
2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/firewall/firewall_iptables_test.go       
2020-01-08 17:26:13.000000000 +0100
@@ -270,6 +270,13 @@
                        Expect(err).NotTo(HaveOccurred())
 
                        validateFullRuleset(fullConf)
+
+                       // ensure creation is idempotent
+                       _, _, err = testutils.CmdAdd(targetNS.Path(), 
args.ContainerID, IFNAME, fullConf, func() error {
+                               return cmdAdd(args)
+                       })
+                       Expect(err).NotTo(HaveOccurred())
+
                        return nil
                })
                Expect(err).NotTo(HaveOccurred())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/plugins/meta/firewall/iptables.go 
new/cni-plugins-0.8.4/plugins/meta/firewall/iptables.go
--- old/cni-plugins-0.8.3/plugins/meta/firewall/iptables.go     2019-11-11 
14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/firewall/iptables.go     2020-01-08 
17:26:13.000000000 +0100
@@ -22,6 +22,7 @@
        "net"
 
        "github.com/containernetworking/cni/pkg/types/current"
+       "github.com/containernetworking/plugins/pkg/utils"
        "github.com/coreos/go-iptables/iptables"
 )
 
@@ -32,20 +33,6 @@
        return rules
 }
 
-func ensureChain(ipt *iptables.IPTables, table, chain string) error {
-       chains, err := ipt.ListChains(table)
-       if err != nil {
-               return fmt.Errorf("failed to list iptables chains: %v", err)
-       }
-       for _, ch := range chains {
-               if ch == chain {
-                       return nil
-               }
-       }
-
-       return ipt.NewChain(table, chain)
-}
-
 func generateFilterRule(privChainName string) []string {
        return []string{"-m", "comment", "--comment", "CNI firewall plugin 
rules", "-j", privChainName}
 }
@@ -73,10 +60,10 @@
        adminRule := generateFilterRule(ib.adminChainName)
 
        // Ensure our private chains exist
-       if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
+       if err := utils.EnsureChain(ipt, "filter", ib.privChainName); err != 
nil {
                return err
        }
-       if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
+       if err := utils.EnsureChain(ipt, "filter", ib.adminChainName); err != 
nil {
                return err
        }
 
@@ -160,10 +147,10 @@
        }
 
        // Ensure our private chains exist
-       if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
+       if err := utils.EnsureChain(ipt, "filter", ib.privChainName); err != 
nil {
                return err
        }
-       if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
+       if err := utils.EnsureChain(ipt, "filter", ib.adminChainName); err != 
nil {
                return err
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/plugins/meta/portmap/chain.go 
new/cni-plugins-0.8.4/plugins/meta/portmap/chain.go
--- old/cni-plugins-0.8.3/plugins/meta/portmap/chain.go 2019-11-11 
14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/portmap/chain.go 2020-01-08 
17:26:13.000000000 +0100
@@ -18,6 +18,7 @@
        "fmt"
        "strings"
 
+       "github.com/containernetworking/plugins/pkg/utils"
        "github.com/coreos/go-iptables/iptables"
        "github.com/mattn/go-shellwords"
 )
@@ -35,16 +36,11 @@
 
 // setup idempotently creates the chain. It will not error if the chain exists.
 func (c *chain) setup(ipt *iptables.IPTables) error {
-       // create the chain
-       exists, err := chainExists(ipt, c.table, c.name)
+
+       err := utils.EnsureChain(ipt, c.table, c.name)
        if err != nil {
                return err
        }
-       if !exists {
-               if err := ipt.NewChain(c.table, c.name); err != nil {
-                       return err
-               }
-       }
 
        // Add the rules to the chain
        for _, rule := range c.rules {
@@ -74,7 +70,7 @@
        // flush the chain
        // This will succeed *and create the chain* if it does not exist.
        // If the chain doesn't exist, the next checks will fail.
-       if err := ipt.ClearChain(c.table, c.name); err != nil {
+       if err := utils.ClearChain(ipt, c.table, c.name); err != nil {
                return err
        }
 
@@ -94,17 +90,15 @@
                                }
                                chainParts = chainParts[2:] // List results 
always include an -A CHAINNAME
 
-                               if err := ipt.Delete(c.table, entryChain, 
chainParts...); err != nil {
-                                       return fmt.Errorf("Failed to delete 
referring rule %s %s: %v", c.table, entryChainRule, err)
+                               if err := utils.DeleteRule(ipt, c.table, 
entryChain, chainParts...); err != nil {
+                                       return err
                                }
+
                        }
                }
        }
 
-       if err := ipt.DeleteChain(c.table, c.name); err != nil {
-               return err
-       }
-       return nil
+       return utils.DeleteChain(ipt, c.table, c.name)
 }
 
 // insertUnique will add a rule to a chain if it does not already exist.
@@ -125,24 +119,10 @@
        }
 }
 
-func chainExists(ipt *iptables.IPTables, tableName, chainName string) (bool, 
error) {
-       chains, err := ipt.ListChains(tableName)
-       if err != nil {
-               return false, err
-       }
-
-       for _, ch := range chains {
-               if ch == chainName {
-                       return true, nil
-               }
-       }
-       return false, nil
-}
-
 // check the chain.
 func (c *chain) check(ipt *iptables.IPTables) error {
 
-       exists, err := chainExists(ipt, c.table, c.name)
+       exists, err := utils.ChainExists(ipt, c.table, c.name)
        if err != nil {
                return err
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/plugins/meta/portmap/chain_test.go 
new/cni-plugins-0.8.4/plugins/meta/portmap/chain_test.go
--- old/cni-plugins-0.8.3/plugins/meta/portmap/chain_test.go    2019-11-11 
14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/portmap/chain_test.go    2020-01-08 
17:26:13.000000000 +0100
@@ -18,6 +18,7 @@
        "fmt"
        "math/rand"
        "runtime"
+       "sync"
 
        "github.com/containernetworking/plugins/pkg/ns"
        "github.com/containernetworking/plugins/pkg/testutils"
@@ -32,6 +33,7 @@
 var _ = Describe("chain tests", func() {
        var testChain chain
        var ipt *iptables.IPTables
+       var testNs ns.NetNS
        var cleanup func()
 
        BeforeEach(func() {
@@ -41,7 +43,7 @@
                currNs, err := ns.GetCurrentNS()
                Expect(err).NotTo(HaveOccurred())
 
-               testNs, err := testutils.NewNS()
+               testNs, err = testutils.NewNS()
                Expect(err).NotTo(HaveOccurred())
 
                tlChainName := fmt.Sprintf("cni-test-%d", rand.Intn(10000000))
@@ -195,4 +197,38 @@
                        }
                }
        })
+
+       It("deletes chains idempotently in parallel", func() {
+               defer cleanup()
+               // number of parallel executions
+               N := 10
+               var wg sync.WaitGroup
+               err := testChain.setup(ipt)
+               Expect(err).NotTo(HaveOccurred())
+               errCh := make(chan error, N)
+               for i := 0; i < N; i++ {
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+                               // teardown chain
+                               errCh <- testNs.Do(func(ns.NetNS) error {
+                                       return testChain.teardown(ipt)
+                               })
+                       }()
+               }
+               wg.Wait()
+               close(errCh)
+               for err := range errCh {
+                       Expect(err).NotTo(HaveOccurred())
+               }
+
+               chains, err := ipt.ListChains(TABLE)
+               Expect(err).NotTo(HaveOccurred())
+               for _, chain := range chains {
+                       if chain == testChain.name {
+                               Fail("Chain was not deleted")
+                       }
+               }
+
+       })
 })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/plugins/meta/portmap/portmap.go 
new/cni-plugins-0.8.4/plugins/meta/portmap/portmap.go
--- old/cni-plugins-0.8.3/plugins/meta/portmap/portmap.go       2019-11-11 
14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/portmap/portmap.go       2020-01-08 
17:26:13.000000000 +0100
@@ -124,7 +124,7 @@
        }
 
        if ip4t != nil {
-               exists, err := chainExists(ip4t, dnatChain.table, 
dnatChain.name)
+               exists, err := utils.ChainExists(ip4t, dnatChain.table, 
dnatChain.name)
                if err != nil {
                        return err
                }
@@ -137,7 +137,7 @@
        }
 
        if ip6t != nil {
-               exists, err := chainExists(ip6t, dnatChain.table, 
dnatChain.name)
+               exists, err := utils.ChainExists(ip6t, dnatChain.table, 
dnatChain.name)
                if err != nil {
                        return err
                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cni-plugins-0.8.3/plugins/meta/portmap/portmap_integ_test.go 
new/cni-plugins-0.8.4/plugins/meta/portmap/portmap_integ_test.go
--- old/cni-plugins-0.8.3/plugins/meta/portmap/portmap_integ_test.go    
2019-11-11 14:07:52.000000000 +0100
+++ new/cni-plugins-0.8.4/plugins/meta/portmap/portmap_integ_test.go    
2020-01-08 17:26:13.000000000 +0100
@@ -96,119 +96,133 @@
                }
        })
 
-       // This needs to be done using Ginkgo's asynchronous testing mode.
-       It("forwards a TCP port on ipv4", func(done Done) {
-               var err error
-               hostPort := rand.Intn(10000) + 1025
-               runtimeConfig := libcni.RuntimeConf{
-                       ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
-                       NetNS:       targetNS.Path(),
-                       IfName:      "eth0",
-                       CapabilityArgs: map[string]interface{}{
-                               "portMappings": []map[string]interface{}{
-                                       {
-                                               "hostPort":      hostPort,
-                                               "containerPort": containerPort,
-                                               "protocol":      "tcp",
+       Describe("Creating an interface in a namespace with the ptp plugin", 
func() {
+               // This needs to be done using Ginkgo's asynchronous testing 
mode.
+               It("forwards a TCP port on ipv4", func(done Done) {
+                       var err error
+                       hostPort := rand.Intn(10000) + 1025
+                       runtimeConfig := libcni.RuntimeConf{
+                               ContainerID: fmt.Sprintf("unit-test-%d", 
hostPort),
+                               NetNS:       targetNS.Path(),
+                               IfName:      "eth0",
+                               CapabilityArgs: map[string]interface{}{
+                                       "portMappings": 
[]map[string]interface{}{
+                                               {
+                                                       "hostPort":      
hostPort,
+                                                       "containerPort": 
containerPort,
+                                                       "protocol":      "tcp",
+                                               },
                                        },
                                },
-                       },
-               }
+                       }
 
-               // Make delete idempotent, so we can clean up on failure
-               netDeleted := false
-               deleteNetwork := func() error {
-                       if netDeleted {
-                               return nil
+                       // Make delete idempotent, so we can clean up on failure
+                       netDeleted := false
+                       deleteNetwork := func() error {
+                               if netDeleted {
+                                       return nil
+                               }
+                               netDeleted = true
+                               return cniConf.DelNetworkList(context.TODO(), 
configList, &runtimeConfig)
                        }
-                       netDeleted = true
-                       return cniConf.DelNetworkList(context.TODO(), 
configList, &runtimeConfig)
-               }
 
-               // we'll also manually check the iptables chains
-               ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
-               Expect(err).NotTo(HaveOccurred())
-               dnatChainName := genDnatChain("cni-portmap-unit-test", 
runtimeConfig.ContainerID).name
-
-               // Create the network
-               resI, err := cniConf.AddNetworkList(context.TODO(), configList, 
&runtimeConfig)
-               Expect(err).NotTo(HaveOccurred())
-               defer deleteNetwork()
-
-               // Undo Docker's forwarding policy
-               cmd := exec.Command("iptables", "-t", "filter",
-                       "-P", "FORWARD", "ACCEPT")
-               cmd.Stderr = GinkgoWriter
-               err = cmd.Run()
-               Expect(err).NotTo(HaveOccurred())
-
-               // Check the chain exists
-               _, err = ipt.List("nat", dnatChainName)
-               Expect(err).NotTo(HaveOccurred())
-
-               result, err := current.GetResult(resI)
-               Expect(err).NotTo(HaveOccurred())
-               var contIP net.IP
-
-               for _, ip := range result.IPs {
-                       intfIndex := *ip.Interface
-                       if result.Interfaces[intfIndex].Sandbox == "" {
-                               continue
+                       // we'll also manually check the iptables chains
+                       ipt, err := 
iptables.NewWithProtocol(iptables.ProtocolIPv4)
+                       Expect(err).NotTo(HaveOccurred())
+                       dnatChainName := genDnatChain("cni-portmap-unit-test", 
runtimeConfig.ContainerID).name
+
+                       // Create the network
+                       resI, err := cniConf.AddNetworkList(context.TODO(), 
configList, &runtimeConfig)
+                       Expect(err).NotTo(HaveOccurred())
+                       defer deleteNetwork()
+
+                       // Undo Docker's forwarding policy
+                       cmd := exec.Command("iptables", "-t", "filter",
+                               "-P", "FORWARD", "ACCEPT")
+                       cmd.Stderr = GinkgoWriter
+                       err = cmd.Run()
+                       Expect(err).NotTo(HaveOccurred())
+
+                       // Check the chain exists
+                       _, err = ipt.List("nat", dnatChainName)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       result, err := current.GetResult(resI)
+                       Expect(err).NotTo(HaveOccurred())
+                       var contIP net.IP
+
+                       for _, ip := range result.IPs {
+                               intfIndex := *ip.Interface
+                               if result.Interfaces[intfIndex].Sandbox == "" {
+                                       continue
+                               }
+                               contIP = ip.Address.IP
+                       }
+                       if contIP == nil {
+                               Fail("could not determine container IP")
                        }
-                       contIP = ip.Address.IP
-               }
-               if contIP == nil {
-                       Fail("could not determine container IP")
-               }
 
-               hostIP := getLocalIP()
-               fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
-                       hostIP, hostPort, contIP, containerPort)
-
-               // dump iptables-save output for debugging
-               cmd = exec.Command("iptables-save")
-               cmd.Stderr = GinkgoWriter
-               cmd.Stdout = GinkgoWriter
-               Expect(cmd.Run()).To(Succeed())
-
-               // Sanity check: verify that the container is reachable directly
-               contOK := testEchoServer(contIP.String(), containerPort, "")
-
-               // Verify that a connection to the forwarded port works
-               dnatOK := testEchoServer(hostIP, hostPort, "")
-
-               // Verify that a connection to localhost works
-               snatOK := testEchoServer("127.0.0.1", hostPort, "")
-
-               // verify that hairpin works
-               hairpinOK := testEchoServer(hostIP, hostPort, targetNS.Path())
-
-               // Cleanup
-               session.Terminate()
-               err = deleteNetwork()
-               Expect(err).NotTo(HaveOccurred())
-
-               // Verify iptables rules are gone
-               _, err = ipt.List("nat", dnatChainName)
-               Expect(err).To(MatchError(ContainSubstring("iptables: No 
chain/target/match by that name.")))
-
-               // Check that everything succeeded *after* we clean up the 
network
-               if !contOK {
-                       Fail("connection direct to " + contIP.String() + " 
failed")
-               }
-               if !dnatOK {
-                       Fail("Connection to " + hostIP + " was not forwarded")
-               }
-               if !snatOK {
-                       Fail("connection to 127.0.0.1 was not forwarded")
-               }
-               if !hairpinOK {
-                       Fail("Hairpin connection failed")
-               }
+                       hostIP := getLocalIP()
+                       fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: 
%s:%d\n",
+                               hostIP, hostPort, contIP, containerPort)
+
+                       // dump iptables-save output for debugging
+                       cmd = exec.Command("iptables-save")
+                       cmd.Stderr = GinkgoWriter
+                       cmd.Stdout = GinkgoWriter
+                       Expect(cmd.Run()).To(Succeed())
+
+                       // dump ip routes output for debugging
+                       cmd = exec.Command("ip", "route")
+                       cmd.Stderr = GinkgoWriter
+                       cmd.Stdout = GinkgoWriter
+                       Expect(cmd.Run()).To(Succeed())
+
+                       // dump ip addresses output for debugging
+                       cmd = exec.Command("ip", "addr")
+                       cmd.Stderr = GinkgoWriter
+                       cmd.Stdout = GinkgoWriter
+                       Expect(cmd.Run()).To(Succeed())
+
+                       // Sanity check: verify that the container is reachable 
directly
+                       contOK := testEchoServer(contIP.String(), 
containerPort, "")
+
+                       // Verify that a connection to the forwarded port works
+                       dnatOK := testEchoServer(hostIP, hostPort, "")
+
+                       // Verify that a connection to localhost works
+                       snatOK := testEchoServer("127.0.0.1", hostPort, "")
+
+                       // verify that hairpin works
+                       hairpinOK := testEchoServer(hostIP, hostPort, 
targetNS.Path())
+
+                       // Cleanup
+                       session.Terminate()
+                       err = deleteNetwork()
+                       Expect(err).NotTo(HaveOccurred())
+
+                       // Verify iptables rules are gone
+                       _, err = ipt.List("nat", dnatChainName)
+                       Expect(err).To(MatchError(ContainSubstring("iptables: 
No chain/target/match by that name.")))
+
+                       // Check that everything succeeded *after* we clean up 
the network
+                       if !contOK {
+                               Fail("connection direct to " + contIP.String() 
+ " failed")
+                       }
+                       if !dnatOK {
+                               Fail("Connection to " + hostIP + " was not 
forwarded")
+                       }
+                       if !snatOK {
+                               Fail("connection to 127.0.0.1 was not 
forwarded")
+                       }
+                       if !hairpinOK {
+                               Fail("Hairpin connection failed")
+                       }
 
-               close(done)
+                       close(done)
 
-       }, TIMEOUT*9)
+               }, TIMEOUT*9)
+       })
 })
 
 // testEchoServer returns true if we found an echo server on the port
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/scripts/release.sh 
new/cni-plugins-0.8.4/scripts/release.sh
--- old/cni-plugins-0.8.3/scripts/release.sh    2019-11-11 14:07:52.000000000 
+0100
+++ new/cni-plugins-0.8.4/scripts/release.sh    2020-01-08 17:26:13.000000000 
+0100
@@ -21,7 +21,7 @@
     apk --no-cache add bash tar;
     cd /go/src/github.com/containernetworking/plugins; umask 0022;
 
-    for arch in amd64 arm arm64 ppc64le s390x; do \
+    for arch in amd64 arm arm64 ppc64le s390x mips64le; do \
         rm -f ${OUTPUT_DIR}/*; \
         CGO_ENABLED=0 GOARCH=\$arch ./build_linux.sh ${BUILDFLAGS}; \
         for format in tgz; do \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cni-plugins-0.8.3/vendor/github.com/coreos/go-iptables/iptables/iptables.go 
new/cni-plugins-0.8.4/vendor/github.com/coreos/go-iptables/iptables/iptables.go
--- 
old/cni-plugins-0.8.3/vendor/github.com/coreos/go-iptables/iptables/iptables.go 
    2019-11-11 14:07:52.000000000 +0100
+++ 
new/cni-plugins-0.8.4/vendor/github.com/coreos/go-iptables/iptables/iptables.go 
    2020-01-08 17:26:13.000000000 +0100
@@ -48,9 +48,13 @@
 
 // IsNotExist returns true if the error is due to the chain or rule not 
existing
 func (e *Error) IsNotExist() bool {
-       return e.ExitStatus() == 1 &&
-               (e.msg == fmt.Sprintf("%s: Bad rule (does a matching rule exist 
in that chain?).\n", getIptablesCommand(e.proto)) ||
-                       e.msg == fmt.Sprintf("%s: No chain/target/match by that 
name.\n", getIptablesCommand(e.proto)))
+       if e.ExitStatus() != 1 {
+               return false
+       }
+       cmdIptables := getIptablesCommand(e.proto)
+       msgNoRuleExist := fmt.Sprintf("%s: Bad rule (does a matching rule exist 
in that chain?).\n", cmdIptables)
+       msgNoChainExist := fmt.Sprintf("%s: No chain/target/match by that 
name.\n", cmdIptables)
+       return strings.Contains(e.msg, msgNoRuleExist) || 
strings.Contains(e.msg, msgNoChainExist)
 }
 
 // Protocol to differentiate between IPv4 and IPv6
@@ -101,7 +105,13 @@
                return nil, err
        }
        vstring, err := getIptablesVersionString(path)
+       if err != nil {
+               return nil, fmt.Errorf("could not get iptables version: %v", 
err)
+       }
        v1, v2, v3, mode, err := extractIptablesVersion(vstring)
+       if err != nil {
+               return nil, fmt.Errorf("failed to extract iptables version from 
[%s]: %v", vstring, err)
+       }
 
        checkPresent, waitPresent, randomFullyPresent := 
getIptablesCommandSupport(v1, v2, v3)
 
@@ -348,18 +358,6 @@
                rules = rules[:len(rules)-1]
        }
 
-       // nftables mode doesn't return an error code when listing a 
non-existent
-       // chain. Patch that up.
-       if len(rules) == 0 && ipt.mode == "nf_tables" {
-               v := 1
-               return nil, &Error{
-                       cmd:        exec.Cmd{Args: args},
-                       msg:        fmt.Sprintf("%s: No chain/target/match by 
that name.\n", getIptablesCommand(ipt.proto)),
-                       proto:      ipt.proto,
-                       exitStatus: &v,
-               }
-       }
-
        for i, rule := range rules {
                rules[i] = filterRuleOutput(rule)
        }
@@ -437,6 +435,7 @@
                }
                ul, err := fmu.tryLock()
                if err != nil {
+                       syscall.Close(fmu.fd)
                        return err
                }
                defer ul.Unlock()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cni-plugins-0.8.3/vendor/modules.txt 
new/cni-plugins-0.8.4/vendor/modules.txt
--- old/cni-plugins-0.8.3/vendor/modules.txt    2019-11-11 14:07:52.000000000 
+0100
+++ new/cni-plugins-0.8.4/vendor/modules.txt    2020-01-08 17:26:13.000000000 
+0100
@@ -32,7 +32,7 @@
 github.com/containernetworking/cni/pkg/version
 github.com/containernetworking/cni/pkg/types/020
 github.com/containernetworking/cni/libcni
-# github.com/coreos/go-iptables v0.4.2
+# github.com/coreos/go-iptables v0.4.5
 github.com/coreos/go-iptables/iptables
 # github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7
 github.com/coreos/go-systemd/activation


Reply via email to