From 7e11ebbc439b00df821154a65869e2b426702c84 Mon Sep 17 00:00:00 2001
From: Mike Brown <brownwm@us.ibm.com>
Date: Tue, 7 Dec 2021 11:57:54 -0600
Subject: [PATCH 1/2] run setup on networks in parallel

Signed-off-by: Mike Brown <brownwm@us.ibm.com>
---
 cni.go | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/cni.go b/cni.go
index 923c280..8b970e8 100644
--- a/cni.go
+++ b/cni.go
@@ -154,16 +154,39 @@ func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...Name
 	return c.createResult(result)
 }
 
+type asynchAttachResult struct {
+	res *types100.Result
+	err error
+}
+
+func asynchAttach(ctx context.Context, n *Network, ns *Namespace, wg *sync.WaitGroup, rc chan asynchAttachResult) {
+	defer wg.Done()
+	r, err := n.Attach(ctx, ns)
+	rc <- asynchAttachResult{res: r, err: err}
+}
+
 func (c *libcni) attachNetworks(ctx context.Context, ns *Namespace) ([]*types100.Result, error) {
+	var wg sync.WaitGroup
+	var lastError error
 	var results []*types100.Result
+	rc := make(chan asynchAttachResult)
+
 	for _, network := range c.Networks() {
-		r, err := network.Attach(ctx, ns)
-		if err != nil {
-			return nil, err
+		wg.Add(1)
+		go asynchAttach(ctx, network, ns, &wg, rc)
+	}
+
+	for range c.Networks() {
+		rs := <-rc
+		if rs.err != nil {
+			lastError = rs.err
+		} else {
+			results = append(results, rs.res)
 		}
-		results = append(results, r)
 	}
-	return results, nil
+	wg.Wait()
+
+	return results, lastError
 }
 
 // Remove removes the network config from the namespace

From 9caf1de13f34a506d1e8e31cafa9388eeb006fe2 Mon Sep 17 00:00:00 2001
From: Mike Brown <brownwm@us.ibm.com>
Date: Tue, 14 Dec 2021 11:45:38 -0600
Subject: [PATCH 2/2] switch to direct index

Signed-off-by: Mike Brown <brownwm@us.ibm.com>
---
 cni.go | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/cni.go b/cni.go
index 8b970e8..f26a6ee 100644
--- a/cni.go
+++ b/cni.go
@@ -155,38 +155,38 @@ func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...Name
 }
 
 type asynchAttachResult struct {
-	res *types100.Result
-	err error
+	index int
+	res   *types100.Result
+	err   error
 }
 
-func asynchAttach(ctx context.Context, n *Network, ns *Namespace, wg *sync.WaitGroup, rc chan asynchAttachResult) {
+func asynchAttach(ctx context.Context, index int, n *Network, ns *Namespace, wg *sync.WaitGroup, rc chan asynchAttachResult) {
 	defer wg.Done()
 	r, err := n.Attach(ctx, ns)
-	rc <- asynchAttachResult{res: r, err: err}
+	rc <- asynchAttachResult{index: index, res: r, err: err}
 }
 
 func (c *libcni) attachNetworks(ctx context.Context, ns *Namespace) ([]*types100.Result, error) {
 	var wg sync.WaitGroup
-	var lastError error
-	var results []*types100.Result
+	var firstError error
+	results := make([]*types100.Result, len(c.Networks()))
 	rc := make(chan asynchAttachResult)
 
-	for _, network := range c.Networks() {
+	for i, network := range c.Networks() {
 		wg.Add(1)
-		go asynchAttach(ctx, network, ns, &wg, rc)
+		go asynchAttach(ctx, i, network, ns, &wg, rc)
 	}
 
 	for range c.Networks() {
 		rs := <-rc
-		if rs.err != nil {
-			lastError = rs.err
-		} else {
-			results = append(results, rs.res)
+		if rs.err != nil && firstError == nil {
+			firstError = rs.err
 		}
+		results[rs.index] = rs.res
 	}
 	wg.Wait()
 
-	return results, lastError
+	return results, firstError
 }
 
 // Remove removes the network config from the namespace