osrg / gobgp

BGP implemented in the Go Programming Language
https://osrg.github.io/gobgp/
Apache License 2.0
3.59k stars 684 forks source link

Route Reflected 'echo' routes still being installed locally #2414

Open mavericm1 opened 3 years ago

mavericm1 commented 3 years ago

This is a continuation of https://github.com/osrg/gobgp/issues/1804

When a route is added and is being reflected by route reflectors after its deleted it doesn't always withdraw the route properly and becomes a wedged route. Accepting these echo routes violates https://tools.ietf.org/html/rfc4271#section-6.3 where the next-hop ip is the ip of the receiver.

quote:

   The IP address in the NEXT_HOP MUST meet the following criteria to be
   considered semantically correct:

      a) It MUST NOT be the IP address of the receiving speaker.

      b) In the case of an EBGP, where the sender and receiver are one
         IP hop away from each other, either the IP address in the
         NEXT_HOP MUST be the sender's IP address that is used to
         establish the BGP connection, or the interface associated with
         the NEXT_HOP IP address MUST share a common subnet with the
         receiving BGP speaker.

   If the NEXT_HOP attribute is semantically incorrect, the error SHOULD
   be logged, and the route SHOULD be ignored.  In this case, a
   NOTIFICATION message SHOULD NOT be sent, and the connection SHOULD
   NOT be closed.

   The AS_PATH attribute is checked for syntactic correctness.  If the
   path is syntactically incorrect, then the Error Subcode MUST be set
   to Malformed AS_PATH.
docker run --rm --name gorr2 -d --network gobgp --ip 192.168.64.101 -v `pwd`/gorr2:/etc/gobgp:rw pierky/gobgp
docker run --rm --name go2 -d --network gobgp --ip 192.168.65.2 -v `pwd`/go2:/etc/gobgp:rw pierky/gobgp

docker exec go2 gobgp global rib add -a ipv4 20.0.0.0/24 aspath 7,1,20,300 local-pref 86

docker exec go2 gobgp global rib 20.0.0.0/24
   Network              Next Hop             AS_PATH              Age        Attrs
*> 20.0.0.0/24          0.0.0.0              7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86}]
*  20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.101} {ClusterList: [192.168.64.100]}]
*  20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.100} {ClusterList: [192.168.64.100]}]

docker exec go2 gobgp global rib del -a ipv4 20.0.0.0/24 aspath 7,1,20,300 local-pref 86
docker exec go2 gobgp global rib 20.0.0.0/24
   Network              Next Hop             AS_PATH              Age        Attrs
*> 20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:26   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.101} {ClusterList: [192.168.64.100]}]
*  20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:26   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.100} {ClusterList: [192.168.64.100]}]

cat gorr2/gobgp.conf
[global.config]
  as = 65000
  router-id = "192.168.64.101"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.64.2"
    peer-as = 65000
    auth-password = "$PASSWORD"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.64.100"
    peer-as = 65000
    auth-password = "$PASSWORD"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.65.1"
    peer-as = 65000
    auth-password = "$PASSWORD"
  [neighbors.route-reflector.config]
    route-reflector-client = true
    route-reflector-cluster-id = "192.168.64.100"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.65.2"
    peer-as = 65000
    auth-password = "$PASSWORD"
  [neighbors.route-reflector.config]
    route-reflector-client = true
    route-reflector-cluster-id = "192.168.64.100"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.65.3"
    peer-as = 65000
    auth-password = "$PASSWORD"
  [neighbors.route-reflector.config]
    route-reflector-client = true
    route-reflector-cluster-id = "192.168.64.100"

cat go2/gobgp.conf
[global.config]
  as = 65000
  router-id = "192.168.65.2"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.64.2"
    peer-as = 65000
    auth-password = "$PASSWORD"
[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.64.100"
    peer-as = 65000
    auth-password = "$PASSWORD"
[[neighbors]]
  [neighbors.config]
    neighbor-address = "192.168.64.101"
    peer-as = 65000
    auth-password = "$PASSWORD"
mavericm1 commented 3 years ago

I'm also noticing that Route Reflection in gobgp seems to set originator incorrectly. Please see https://tools.ietf.org/html/rfc4456#section-8

8.  Avoiding Routing Information Loops

   When a route is reflected, it is possible through misconfiguration to
   form route re-distribution loops.  The route reflection method
   defines the following attributes to detect and avoid routing
   information loops:

   ORIGINATOR_ID

   ORIGINATOR_ID is a new optional, non-transitive BGP attribute of Type
   code 9.  This attribute is 4 bytes long and it will be created by an
   RR in reflecting a route.  This attribute will carry the BGP
   Identifier of the originator of the route in the local AS.  A BGP
   speaker SHOULD NOT create an ORIGINATOR_ID attribute if one already
   exists.  A router that recognizes the ORIGINATOR_ID attribute SHOULD
   ignore a route received with its BGP Identifier as the ORIGINATOR_ID.

   CLUSTER_LIST

   CLUSTER_LIST is a new, optional, non-transitive BGP attribute of Type
   code 10.  It is a sequence of CLUSTER_ID values representing the
   reflection path that the route has passed.

   When an RR reflects a route, it MUST prepend the local CLUSTER_ID to
   the CLUSTER_LIST.  If the CLUSTER_LIST is empty, it MUST create a new
   one.  Using this attribute an RR can identify if the routing
   information has looped back to the same cluster due to
   misconfiguration.  If the local CLUSTER_ID is found in the
   CLUSTER_LIST, the advertisement received SHOULD be ignored.

When gobgp receives a route from a rrclient and reflects the route it sets its own ip to the originator vs that of the client.

docker exec go2 gobgp global rib 20.0.0.0/24
   Network              Next Hop             AS_PATH              Age        Attrs
*> 20.0.0.0/24          0.0.0.0              7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86}]
*  20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.101} {ClusterList: [192.168.64.100]}]
*  20.0.0.0/24          192.168.65.2         7 1 20 300        00:00:04   [{Origin: ?} {LocalPref: 86} {Originator: 192.168.64.100} {ClusterList: [192.168.64.100]}]