diff --git a/protocols/bgp/packet/community.go b/protocols/bgp/packet/community.go
index 5fd0f29a3bb95c685de17e5bab067151dc03e13c..6f4e2a67ab3b074117211e28a84d6da2188da3d9 100644
--- a/protocols/bgp/packet/community.go
+++ b/protocols/bgp/packet/community.go
@@ -6,6 +6,11 @@ import (
 	"strings"
 )
 
+const (
+	WellKnownCommunityNoExport    = 0xFFFFFF01
+	WellKnownCommunityNoAdvertise = 0xFFFFFF02
+)
+
 func CommunityStringForUint32(v uint32) string {
 	e1 := v >> 16
 	e2 := v - e1<<16
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index b5b554dd60f5302b09a68bc5f37744137013f281..20be5160eff16fb132ffe45ed1a2875b0d333fdb 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -723,6 +723,7 @@ func (fsm *FSM) established() int {
 	n := &routingtable.Neighbor{
 		Type:    route.BGPPathType,
 		Address: tnet.IPv4ToUint32(fsm.remote),
+		IBGP:    fsm.remoteASN == fsm.localASN,
 	}
 
 	clientOptions := routingtable.ClientOptions{
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index 51347119a6b360fd2f81283edc18d9225548fdf2..fe728f0e64981276e38322ec3985b467180ee05f 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -35,7 +35,7 @@ func (a *AdjRIBOut) UpdateNewClient(client routingtable.RouteTableClient) error
 
 // AddPath replaces the path for prefix `pfx`. If the prefix doesn't exist it is added.
 func (a *AdjRIBOut) AddPath(pfx net.Prefix, p *route.Path) error {
-	if a.isOwnPath(p) {
+	if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) {
 		return nil
 	}
 
@@ -56,7 +56,7 @@ func (a *AdjRIBOut) AddPath(pfx net.Prefix, p *route.Path) error {
 
 // RemovePath removes the path for prefix `pfx`
 func (a *AdjRIBOut) RemovePath(pfx net.Prefix, p *route.Path) bool {
-	if a.isOwnPath(p) {
+	if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) {
 		return false
 	}
 
@@ -77,19 +77,6 @@ func (a *AdjRIBOut) RemovePath(pfx net.Prefix, p *route.Path) bool {
 	return true
 }
 
-func (a *AdjRIBOut) isOwnPath(p *route.Path) bool {
-	if p.Type != a.neighbor.Type {
-		return false
-	}
-
-	switch p.Type {
-	case route.BGPPathType:
-		return p.BGPPath.Source == a.neighbor.Address
-	}
-
-	return false
-}
-
 func (a *AdjRIBOut) removePathsFromClients(pfx net.Prefix, paths []*route.Path) {
 	for _, path := range paths {
 		for _, client := range a.ClientManager.Clients() {
diff --git a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
index 90f76fcc873643a6d94086b0b84f5bf940b6fa9f..f0c75c0b74ac84d43a6b2cb257ed18504ccc51ef 100644
--- a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
+++ b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
@@ -37,7 +37,7 @@ func (a *AdjRIBOutAddPath) UpdateNewClient(client routingtable.RouteTableClient)
 
 // AddPath adds path p to prefix `pfx`
 func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error {
-	if a.isOwnPath(p) {
+	if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) {
 		return nil
 	}
 
@@ -63,7 +63,7 @@ func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error {
 
 // RemovePath removes the path for prefix `pfx`
 func (a *AdjRIBOutAddPath) RemovePath(pfx net.Prefix, p *route.Path) bool {
-	if a.isOwnPath(p) {
+	if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) {
 		return false
 	}
 
diff --git a/routingtable/neighbor.go b/routingtable/neighbor.go
index c7702ea49cb8f52fd43fd61d3bbf9f50c05782d7..7ae0f7395637c3a2f7bcf9de4a890edf804c982b 100644
--- a/routingtable/neighbor.go
+++ b/routingtable/neighbor.go
@@ -7,4 +7,7 @@ type Neighbor struct {
 
 	// Type is the type / protocol used for routing inforation communitation
 	Type uint8
+
+	// IBGP returns if local ASN is equal to remote ASN
+	IBGP bool
 }
diff --git a/routingtable/update_helper.go b/routingtable/update_helper.go
new file mode 100644
index 0000000000000000000000000000000000000000..c18936f3a21055678401a9ec4697ab00363fc4f0
--- /dev/null
+++ b/routingtable/update_helper.go
@@ -0,0 +1,52 @@
+package routingtable
+
+import (
+	"strings"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/bio-routing/bio-rd/route"
+	log "github.com/sirupsen/logrus"
+)
+
+// ShouldPropagateUpdate performs some default checks and returns if an route update should be propagated to a neighbor
+func ShouldPropagateUpdate(pfx net.Prefix, p *route.Path, n *Neighbor) bool {
+	return !isOwnPath(p, n) && !isDisallowedByCommunity(p, n)
+}
+
+func isOwnPath(p *route.Path, n *Neighbor) bool {
+	if p.Type != n.Type {
+		return false
+	}
+
+	switch p.Type {
+	case route.BGPPathType:
+		return p.BGPPath.Source == n.Address
+	}
+
+	return false
+}
+
+func isDisallowedByCommunity(p *route.Path, n *Neighbor) bool {
+	if p.BGPPath == nil || len(p.BGPPath.Communities) == 0 {
+		return false
+	}
+
+	strs := strings.Split(p.BGPPath.Communities, " ")
+	for _, str := range strs {
+		com, err := packet.ParseCommunityString(str)
+		if err != nil {
+			log.WithField("Sender", "routingtable.ShouldAnnounce()").
+				WithField("community", str).
+				WithError(err).
+				Error("Could not parse community")
+			continue
+		}
+
+		if (com == packet.WellKnownCommunityNoExport && !n.IBGP) || com == packet.WellKnownCommunityNoAdvertise {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/routingtable/update_helper_test.go b/routingtable/update_helper_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..29342f376ead000006039e6aa95caf3399937dc1
--- /dev/null
+++ b/routingtable/update_helper_test.go
@@ -0,0 +1,76 @@
+package routingtable
+
+import (
+	"net"
+	"testing"
+
+	bnet "github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestShouldPropagateUpdate(t *testing.T) {
+	tests := []struct {
+		name        string
+		communities string
+		neighbor    Neighbor
+		expected    bool
+	}{
+		{
+			name:     "arbitrary path",
+			expected: true,
+		},
+		{
+			name:        "path was received from this peer before",
+			communities: "(1,2)",
+			neighbor: Neighbor{
+				Type:    route.BGPPathType,
+				Address: bnet.IPv4ToUint32(net.ParseIP("192.168.1.1")),
+			},
+			expected: false,
+		},
+		{
+			name:        "path with no-export community",
+			communities: "(1,2) (65535,65281)",
+			expected:    false,
+		},
+		{
+			name:        "path with no-export community (iBGP)",
+			communities: "(1,2) (65535,65281)",
+			neighbor: Neighbor{
+				IBGP: true,
+			},
+			expected: true,
+		},
+		{
+			name:        "path with no-advertise community",
+			communities: "(1,2) (65535,65282)",
+			expected:    false,
+		},
+		{
+			name:        "path with no-advertise community (iBGP)",
+			communities: "(1,2) (65535,65282)",
+			neighbor: Neighbor{
+				IBGP: true,
+			},
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			pfx := bnet.NewPfx(0, 32)
+
+			pa := &route.Path{
+				Type: route.BGPPathType,
+				BGPPath: &route.BGPPath{
+					Communities: test.communities,
+					Source:      bnet.IPv4ToUint32(net.ParseIP("192.168.1.1")),
+				},
+			}
+
+			res := ShouldPropagateUpdate(pfx, pa, &test.neighbor)
+			assert.Equal(te, test.expected, res)
+		})
+	}
+}