--- /dev/null
+From dbc3fbc612ce6523a596804c270600de1f6f2309 Mon Sep 17 00:00:00 2001
+From: Mitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>
+Date: Thu, 15 Feb 2018 17:20:27 -0800
+Subject: [PATCH] bgpd: support for default-originate type-5 route
+
+Implement support for 'default-originate' for L2VPN/EVPN address family.
+This is needed for the case where external routing within a POD,
+will follow the default route to the border/exit leaf.
+The border/exit leaf has more than one next hop to forward the packet on to,
+depending on the destination IP.
+
+Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
+---
+ bgpd/bgp_evpn_private.h | 14 ++++++++
+ bgpd/bgp_evpn_vty.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++
+ bgpd/bgpd.h | 2 ++
+ 3 files changed, 105 insertions(+)
+
+diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
+index 5ff16c3..bc68e25 100644
+--- a/bgpd/bgp_evpn_private.h
++++ b/bgpd/bgp_evpn_private.h
+@@ -349,6 +349,20 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
+ p->prefix.ip.ipaddr_v4 = originator_ip;
+ }
+
++static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
++ safi_t safi)
++{
++ if (afi == AFI_IP &&
++ CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
++ return 1;
++ else if (afi == AFI_IP6 &&
++ CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
++ return 1;
++ return 0;
++}
++
+ extern void evpn_rt_delete_auto(struct bgp*, vni_t, struct list*);
+ extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomadd);
+diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
+index 1720744..5ce71db 100644
+--- a/bgpd/bgp_evpn_vty.c
++++ b/bgpd/bgp_evpn_vty.c
+@@ -2476,6 +2476,48 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
+ /*
+ * evpn - enable advertisement of default g/w
+ */
++static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf,
++ afi_t afi, int add)
++{
++ struct prefix ip_prefix;
++ safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */
++
++ /* form the default prefix 0.0.0.0/0 */
++ memset(&ip_prefix, 0, sizeof(struct prefix));
++ ip_prefix.family = afi2family(afi);
++ ip_prefix.prefixlen = 0;
++
++ if (add) {
++ /* bail if we are already advertising default route */
++ if (evpn_default_originate_set(bgp_vrf, afi, safi))
++ return;
++
++ if (afi == AFI_IP)
++ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
++ else if (afi == AFI_IP6)
++ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
++ bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
++ NULL, afi, safi);
++ } else {
++ /* bail out if we havent advertised the default route */
++ if (!evpn_default_originate_set(bgp_vrf, afi, safi))
++ return;
++ if (afi == AFI_IP)
++ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
++ else if (afi == AFI_IP6)
++ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
++ bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
++ afi, safi);
++ }
++}
++
++/*
++ * evpn - enable advertisement of default g/w
++ */
+ static void evpn_set_advertise_subnet(struct bgp *bgp,
+ struct bgpevpn *vpn)
+ {
+@@ -2671,6 +2713,43 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
+ return CMD_SUCCESS;
+ }
+
++DEFUN (bgp_evpn_default_originate,
++ bgp_evpn_default_originate_cmd,
++ "default-originate <ipv4 | ipv6>",
++ "originate a default route\n"
++ "ipv4 address family\n"
++ "ipv6 address family\n")
++{
++ afi_t afi = 0;
++ int idx_afi = 0;
++ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
++
++ if (!bgp_vrf)
++ return CMD_WARNING;
++ argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
++ evpn_process_default_originate_cmd(bgp_vrf, afi, 1);
++ return CMD_SUCCESS;
++}
++
++DEFUN (no_bgp_evpn_default_originate,
++ no_bgp_evpn_default_originate_cmd,
++ "no default-originate <ipv4 | ipv6>",
++ NO_STR
++ "withdraw a default route\n"
++ "ipv4 address family\n"
++ "ipv6 address family\n")
++{
++ afi_t afi = 0;
++ int idx_afi = 0;
++ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
++
++ if (!bgp_vrf)
++ return CMD_WARNING;
++ argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
++ evpn_process_default_originate_cmd(bgp_vrf, afi, 0);
++ return CMD_SUCCESS;
++}
++
+ DEFUN (bgp_evpn_advertise_vni_subnet,
+ bgp_evpn_advertise_vni_subnet_cmd,
+ "advertise-subnet",
+@@ -4382,6 +4461,14 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
+ if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
+ vty_out(vty, " advertise ipv6 unicast\n");
++
++ if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
++ vty_out(vty, " default-originate ipv4\n");
++
++ if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
++ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
++ vty_out(vty, " default-originate ipv6\n");
+ }
+
+ void bgp_ethernetvpn_init(void)
+@@ -4411,6 +4498,8 @@ void bgp_ethernetvpn_init(void)
+ install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
+ install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
++ install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
++ install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
+
+ /* "show bgp l2vpn evpn" commands. */
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
+diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
+index 5b77be2..274ca82 100644
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -323,6 +323,8 @@ struct bgp {
+ /* l2vpn evpn flags */
+ #define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 0)
+ #define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST (1 << 1)
++#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 2)
++#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 3)
+
+
+ /* Route table for next-hop lookup cache. */
+--
+2.7.4
+
return;
}
+/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf,
+ afi_t afi, int add)
+{
+ struct prefix ip_prefix;
+ safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */
+
+ /* form the default prefix 0.0.0.0/0 */
+ memset(&ip_prefix, 0, sizeof(struct prefix));
+ ip_prefix.family = afi2family(afi);
+ ip_prefix.prefixlen = 0;
+
+ if (add) {
+ /* bail if we are already advertising default route */
+ if (evpn_default_originate_set(bgp_vrf, afi, safi))
+ return;
+
+ if (afi == AFI_IP)
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
+ else if (afi == AFI_IP6)
+ SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
+ bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
+ NULL, afi, safi);
+ } else {
+ /* bail out if we havent advertised the default route */
+ if (!evpn_default_originate_set(bgp_vrf, afi, safi))
+ return;
+ if (afi == AFI_IP)
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
+ else if (afi == AFI_IP6)
+ UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
+ bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
+ afi, safi);
+ }
+}
+
/*
* evpn - enable advertisement of default g/w
*/
return CMD_SUCCESS;
}
+DEFUN (bgp_evpn_default_originate,
+ bgp_evpn_default_originate_cmd,
+ "default-originate <ipv4 | ipv6>",
+ "originate a default route\n"
+ "ipv4 address family\n"
+ "ipv6 address family\n")
+{
+ afi_t afi = 0;
+ int idx_afi = 0;
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp_vrf)
+ return CMD_WARNING;
+ argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
+ evpn_process_default_originate_cmd(bgp_vrf, afi, 1);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_default_originate,
+ no_bgp_evpn_default_originate_cmd,
+ "no default-originate <ipv4 | ipv6>",
+ NO_STR
+ "withdraw a default route\n"
+ "ipv4 address family\n"
+ "ipv6 address family\n")
+{
+ afi_t afi = 0;
+ int idx_afi = 0;
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp_vrf)
+ return CMD_WARNING;
+ argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
+ evpn_process_default_originate_cmd(bgp_vrf, afi, 0);
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_evpn_advertise_vni_subnet,
bgp_evpn_advertise_vni_subnet_cmd,
"advertise-subnet",
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
vty_out(vty, " advertise ipv6 unicast\n");
+
+ if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
+ vty_out(vty, " default-originate ipv4\n");
+
+ if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+ BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
+ vty_out(vty, " default-originate ipv6\n");
}
void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
+ install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
/* "show bgp l2vpn evpn" commands. */
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);