From f3f2d1b852e17d6cfb823d08e39d86b6c15ea177 Mon Sep 17 00:00:00 2001
From: Maximilian Wilhelm <max@sdn.clinic>
Date: Sun, 1 Jul 2018 23:08:01 +0200
Subject: [PATCH] Remove all path for a prefix from an AddPath capabale
 neighbor if a path with NO_EXPORT/NO_ADVERTISE shows up.

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
---
 routingtable/adjRIBOut/adj_rib_out.go | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index a2179fc0..2685ce37 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -47,6 +47,9 @@ func (a *AdjRIBOut) RouteCount() int64 {
 // AddPath adds path p to prefix `pfx`
 func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 	if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) {
+		if a.neighbor.CapAddPathRX {
+			a.removePathsForPrefix(pfx)
+		}
 		return nil
 	}
 
@@ -55,6 +58,7 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 		return nil
 	}
 
+	// If the neighbor is an eBGP peer and not a Route Server client modify ASPath and Next Hop
 	p = p.Copy()
 	if !a.neighbor.IBGP && !a.neighbor.RouteServerClient {
 		p.BGPPath.Prepend(a.neighbor.LocalASN, 1)
@@ -130,6 +134,25 @@ func (a *AdjRIBOut) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
 	return true
 }
 
+func (a *AdjRIBOut) removePathsForPrefix(pfx bnet.Prefix) bool {
+	// We were called before a.AddPath() had a lock, so we need to lock here and release it
+	// after the get to prevent a dead lock as RemovePath() will acquire a lock itself!
+	a.mu.Lock()
+	r := a.rt.Get(pfx)
+	a.mu.Unlock()
+
+	// If no path with this prefix is present, we're done
+	if r == nil {
+		return false
+	}
+
+	for _, path := range r.Paths() {
+		a.RemovePath(pfx, path)
+	}
+
+	return true
+}
+
 func (a *AdjRIBOut) isOwnPath(p *route.Path) bool {
 	if p.Type != a.neighbor.Type {
 		return false
-- 
GitLab