From: Daniel Walton <[email protected]>

Allow the replacement of a specific AS with another.

Signed-off-by: Daniel Walton <[email protected]>
---
 bgpd/bgp_aspath.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 bgpd/bgp_aspath.h |  2 ++
 bgpd/bgp_route.c  | 15 +++++++++++++++
 bgpd/bgp_vty.c    | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 bgpd/bgpd.c       | 11 +++++++++++
 bgpd/bgpd.h       |  4 +++-
 6 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 776f6e6..aace91b 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1167,6 +1167,58 @@ aspath_private_as_check (struct aspath *aspath)
   return 1;
 }
 
+/* Return True if the entire ASPATH consist of the specified ASN */
+int
+aspath_single_asn_check (struct aspath *aspath, as_t asn)
+{
+  struct assegment *seg;
+
+  if ( !(aspath && aspath->segments) )
+    return 0;
+
+  seg = aspath->segments;
+
+  while (seg)
+    {
+      int i;
+
+      for (i = 0; i < seg->length; i++)
+       {
+         if (seg->as[i] != asn)
+           return 0;
+       }
+      seg = seg->next;
+    }
+  return 1;
+}
+
+/* Replace all instances of the target ASN with our own ASN */
+struct aspath *
+aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn,
+                             as_t our_asn)
+{
+  struct aspath *new;
+  struct assegment *seg;
+
+  new = aspath_dup(aspath);
+  seg = new->segments;
+
+  while (seg)
+    {
+      int i;
+
+      for (i = 0; i < seg->length; i++)
+       {
+         if (seg->as[i] == target_asn)
+            seg->as[i] = our_asn;
+       }
+      seg = seg->next;
+    }
+
+  aspath_str_update(new);
+  return new;
+}
+
 /* Replace all private ASNs with our own ASN */
 struct aspath *
 aspath_replace_private_asns (struct aspath *aspath, as_t asn)
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 7280f31..134f1f6 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -98,6 +98,8 @@ extern void aspath_print_all_vty (struct vty *);
 extern unsigned int aspath_key_make (void *);
 extern int aspath_loop_check (struct aspath *, as_t);
 extern int aspath_private_as_check (struct aspath *);
+extern int aspath_single_asn_check (struct aspath *, as_t asn);
+extern struct aspath *aspath_replace_specific_asn (struct aspath *aspath, as_t 
target_asn, as_t our_asn);
 extern struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t 
asn);
 extern struct aspath *aspath_remove_private_asns (struct aspath *aspath);
 extern int aspath_firstas_check (struct aspath *, as_t);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index f48cfed..ab81b72 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -915,6 +915,19 @@ bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, 
safi_t safi,
     }
 }
 
+/* If this is an EBGP peer with as-override */
+static void
+bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
+                     struct peer *peer, struct attr *attr)
+{
+  if (peer->sort == BGP_PEER_EBGP &&
+      peer_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE))
+    {
+      if (aspath_single_asn_check (attr->aspath, peer->as))
+        attr->aspath = aspath_replace_specific_asn (attr->aspath, peer->as, 
bgp->as);
+    }
+}
+
 static int
 bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
                    struct attr *attr, afi_t afi, safi_t safi)
@@ -1177,6 +1190,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer 
*peer, struct prefix *p,
 #endif /* HAVE_IPV6 */
 
   bgp_peer_remove_private_as(bgp, afi, safi, peer, attr);
+  bgp_peer_as_override(bgp, afi, safi, peer, attr);
 
   /* Route map & unsuppress-map apply. */
   if (ROUTE_MAP_OUT_NAME (filter)
@@ -1384,6 +1398,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct 
peer *rsclient,
 #endif /* HAVE_IPV6 */
 
   bgp_peer_remove_private_as(bgp, afi, safi, rsclient, attr);
+  bgp_peer_as_override(bgp, afi, safi, rsclient, attr);
 
   /* Route map & unsuppress-map apply. */
   if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) )
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index bdc149a..7bec815 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -232,6 +232,9 @@ bgp_vty_return (struct vty *vty, int ret)
     case BGP_ERR_NO_IBGP_WITH_TTLHACK:
       str = "ttl-security only allowed for EBGP peers";
       break;
+    case BGP_ERR_AS_OVERRIDE:
+      str = "as-override cannot be configured for IBGP peers";
+      break;
     }
   if (str)
     {
@@ -2636,6 +2639,32 @@ DEFUN (no_neighbor_nexthop_self,
                                 
PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL);
 }
 
+/* neighbor as-override */
+DEFUN (neighbor_as_override,
+       neighbor_as_override_cmd,
+       NEIGHBOR_CMD2 "as-override",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Override ASNs in outbound updates if aspath equals remote-as\n")
+{
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                               bgp_node_safi (vty),
+                               PEER_FLAG_AS_OVERRIDE);
+}
+
+DEFUN (no_neighbor_as_override,
+       no_neighbor_as_override_cmd,
+       NO_NEIGHBOR_CMD2 "as-override",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Override ASNs in outbound updates if aspath equals remote-as\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                 bgp_node_safi (vty),
+                                 PEER_FLAG_AS_OVERRIDE);
+}
+
 /* neighbor remove-private-AS. */
 DEFUN (neighbor_remove_private_as,
        neighbor_remove_private_as_cmd,
@@ -8256,6 +8285,9 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t 
afi, safi_t safi)
   else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
     vty_out (vty, "  Private AS numbers removed in updates to this 
neighbor%s", VTY_NEWLINE);
 
+  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
+    vty_out (vty, "  Override ASNs in outbound updates if aspath equals 
remote-as%s", VTY_NEWLINE);
+
   if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) ||
       CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL))
     vty_out (vty, "  NEXT_HOP is always this router%s", VTY_NEWLINE);
@@ -10331,6 +10363,20 @@ bgp_vty_init (void)
   install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
 
+  /* "neighbor as-override" commands. */
+  install_element (BGP_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV6M_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV6M_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_as_override_cmd);
+
   /* "neighbor remove-private-AS" commands. */
   install_element (BGP_NODE, &neighbor_remove_private_as_cmd);
   install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index cc2abb5..78f9a2c 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2713,6 +2713,7 @@ static const struct peer_flag_action 
peer_af_flag_action_list[] =
     { PEER_FLAG_ORF_PREFIX_RM,            1, peer_change_reset },
     { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED,  0, peer_change_reset_out },
     { PEER_FLAG_NEXTHOP_SELF_ALL,         1, peer_change_reset_out },
+    { PEER_FLAG_AS_OVERRIDE,              1, peer_change_reset_out },
     { 0, 0, 0 }
   };
 
@@ -2956,6 +2957,11 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, 
safi_t safi, u_int32_t flag,
       && peer_sort (peer) == BGP_PEER_IBGP)
     return BGP_ERR_REMOVE_PRIVATE_AS;
 
+  /* as-override is not allowed for IBGP peers */
+  if (flag & PEER_FLAG_AS_OVERRIDE
+      && peer_sort (peer) == BGP_PEER_IBGP)
+    return BGP_ERR_AS_OVERRIDE;
+
   /* When unset the peer-group member's flag we have to check
      peer-group configuration.  */
   if (! set && peer->af_group[afi][safi])
@@ -5523,6 +5529,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
         vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE);
     }
 
+  /* as-override */
+  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE) &&
+      !peer->af_group[afi][safi])
+    vty_out (vty, " neighbor %s as-override%s", addr, VTY_NEWLINE);
+
   /* send-community print. */
   if (! peer->af_group[afi][safi])
     {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index ec73ae1..afe2b50 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -489,6 +489,7 @@ struct peer
 #define PEER_FLAG_NEXTHOP_SELF_ALL          (1 << 17) /* next-hop-self all */
 #define PEER_FLAG_REMOVE_PRIVATE_AS_ALL     (1 << 18) /* remove-private-as all 
*/
 #define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as 
replace-as */
+#define PEER_FLAG_AS_OVERRIDE               (1 << 20) /* as-override */
 
   /* MD5 password */
   char *password;
@@ -907,7 +908,8 @@ enum bgp_clear_type
 #define BGP_ERR_NO_IBGP_WITH_TTLHACK           -31
 #define BGP_ERR_NO_INTERFACE_CONFIG             -32
 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS    -33
-#define BGP_ERR_MAX                            -34
+#define BGP_ERR_AS_OVERRIDE                     -34
+#define BGP_ERR_MAX                            -35
 
 extern struct bgp_master *bm;
 
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to