From 8ffedceac3aa64f98f3da3c64bd215926bdc0d5e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 22 Jul 2015 12:35:37 -0700 Subject: [PATCH] bgpd-interface-ipv4-cmd.patch BGP: Determine peer's IP address if interface has /30, /31 Allow interface-based session config for IPv4 numbered links if the link address is either /30 or /31. This is not RFC5549, but can be deployed now, and independent of whether the peer supports RFC5549 or not. Signed-off-by: Dinesh G Dutt Reviewed-By: Vivek Venkataram --- bgpd/bgp_nexthop.c | 19 +++++++ bgpd/bgp_vty.c | 17 +++++-- bgpd/bgpd.c | 124 ++++++++++++++++++++++++++++++++++++++------- bgpd/bgpd.h | 5 +- 4 files changed, 141 insertions(+), 24 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 40b719fe31..658a4b1fd5 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_nht.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_damp.h" +#include "bgpd/bgp_fsm.h" #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ @@ -204,6 +205,10 @@ bgp_connected_add (struct connected *ifc) struct prefix *addr; struct bgp_node *rn; struct bgp_connected_ref *bc; + struct listnode *node, *nnode, *mnode; + struct bgp *bgp; + struct peer *peer; + u_int32_t saddr; addr = ifc->address; @@ -229,6 +234,20 @@ bgp_connected_add (struct connected *ifc) bc->refcnt = 1; rn->info = bc; } + + for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) + { + for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) + { + if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0) && + !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) + { + if (peer_active(peer)) + BGP_EVENT_ADD (peer, BGP_Stop); + BGP_EVENT_ADD (peer, BGP_Start); + } + } + } } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 96ebf4f58c..c69ef0831a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2611,10 +2611,11 @@ DEFUN (neighbor_remote_as, DEFUN (neighbor_interface_config, neighbor_interface_config_cmd, - "neighbor WORD interface", + "neighbor WORD interface {v6only}", NEIGHBOR_STR "Interface name or neighbor tag\n" - "Enable BGP on interface\n") + "Enable BGP on interface\n" + "Enable BGP with v6 link-local only\n") { struct bgp *bgp; struct peer *peer; @@ -2628,7 +2629,10 @@ DEFUN (neighbor_interface_config, return CMD_WARNING; } - peer = peer_conf_interface_get (bgp, argv[0], AFI_IP, SAFI_UNICAST); + if (argv[1] != NULL) + peer = peer_conf_interface_get (bgp, argv[0], AFI_IP, SAFI_UNICAST, 1); + else + peer = peer_conf_interface_get (bgp, argv[0], AFI_IP, SAFI_UNICAST, 0); if (!peer) return CMD_WARNING; @@ -4979,12 +4983,15 @@ DEFUN (neighbor_interface, "Interface\n" "Interface name\n") { - return peer_interface_vty (vty, argv[0], argv[1]); + if (argc == 3) + return peer_interface_vty (vty, argv[0], argv[1]); + else + return peer_interface_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_interface, no_neighbor_interface_cmd, - NO_NEIGHBOR_CMD "interface WORD", + NO_NEIGHBOR_CMD2 "interface WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 380a45559d..5a633ed60f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -782,6 +782,9 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) static void peer_global_config_reset (struct peer *peer) { + + int v6only; + peer->weight = 0; peer->change_local_as = 0; peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); @@ -801,7 +804,14 @@ peer_global_config_reset (struct peer *peer) else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + /* This is a per-peer specific flag and so we must preserve it */ + v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + peer->flags = 0; + + if (v6only) + SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + peer->config = 0; peer->holdtime = 0; peer->keepalive = 0; @@ -1163,30 +1173,74 @@ void bgp_peer_conf_if_to_su_update (struct peer *peer) { struct interface *ifp; - struct nbr_connected *ifc; + struct nbr_connected *ifc_nbr; + struct connected *ifc; + struct prefix p; + u_int32_t s_addr; + struct listnode *node; if (!peer->conf_if) return; - if ((ifp = if_lookup_by_name(peer->conf_if)) && - ifp->nbr_connected && - (ifc = listnode_head(ifp->nbr_connected))) + if (ifp = if_lookup_by_name(peer->conf_if)) { - peer->su.sa.sa_family = AF_INET6; - memcpy(&peer->su.sin6.sin6_addr, &ifc->address->u.prefix, - sizeof (struct in6_addr)); + /* if multiple IP addresses assigned to link, we pick the first */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + if (ifc->address && (ifc->address->family == AF_INET)) + { + /* Try IPv4 connection first, if present */ + PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); + /* We can determine peer's IP address if prefixlen is 30/31 */ + if (p.prefixlen == 30) + { + peer->su.sa.sa_family = AF_INET; + s_addr = ntohl(p.u.prefix4.s_addr); + if (s_addr % 4 == 1) + peer->su.sin.sin_addr.s_addr = htonl(s_addr+1); + else if (s_addr % 4 == 2) + peer->su.sin.sin_addr.s_addr = htonl(s_addr-1); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer->su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + return; + } + else if (p.prefixlen == 31) + { + peer->su.sa.sa_family = AF_INET; + s_addr = ntohl(p.u.prefix4.s_addr); + if (s_addr % 2 == 0) + peer->su.sin.sin_addr.s_addr = htonl(s_addr+1); + else + peer->su.sin.sin_addr.s_addr = htonl(s_addr-1); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer->su->sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + return; + } + else + zlog_warn("%s neighbor interface with IPv4 numbered links used without /30 or /31", + peer->conf_if); + } + + if (ifp->nbr_connected && + (ifc_nbr = listnode_head(ifp->nbr_connected))) + { + peer->su.sa.sa_family = AF_INET6; + memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix, + sizeof (struct in6_addr)); #ifdef SIN6_LEN - peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6); + peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6); #endif - peer->su.sin6.sin6_scope_id = ifp->ifindex; - } - else - { - /* This works as an indication of unresolved peer address - on a BGP interface*/ - peer->su.sa.sa_family = AF_UNSPEC; - memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr)); + peer->su.sin6.sin6_scope_id = ifp->ifindex; + + return; + } } + /* This works as an indication of unresolved peer address + on a BGP interface*/ + peer->su.sa.sa_family = AF_UNSPEC; + memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr)); } /* Create new BGP peer. */ @@ -1255,7 +1309,7 @@ peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp, struct peer * peer_conf_interface_get(struct bgp *bgp, const char *conf_if, afi_t afi, - safi_t safi) + safi_t safi, int v6only) { struct peer *peer; @@ -1268,6 +1322,26 @@ peer_conf_interface_get(struct bgp *bgp, const char *conf_if, afi_t afi, else peer = peer_create (NULL, conf_if, bgp, bgp->as, AS_SPECIFIED, 0, afi, safi); + if (peer && v6only) + SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + } + else if ((v6only && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) || + (!v6only && CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))) + { + if (v6only) + SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + else + UNSET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + + /* v6only flag changed. Reset bgp seesion */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + { + peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + bgp_notify_send (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + else + bgp_session_reset(peer); } return peer; @@ -1845,6 +1919,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, struct peer *conf; struct bgp_filter *pfilter; struct bgp_filter *gfilter; + int v6only; conf = group->conf; pfilter = &peer->filter[afi][safi]; @@ -1867,8 +1942,15 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, /* Weight */ peer->weight = conf->weight; + /* this flag is per-neighbor and so has to be preserved */ + v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + /* peer flags apply */ peer->flags = conf->flags; + + if (v6only) + SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + /* peer af_flags apply */ peer->af_flags[afi][safi] = conf->af_flags[afi][safi]; /* peer config apply */ @@ -2446,6 +2528,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, struct peer_group *group, afi_t afi, safi_t safi) { struct peer *other; + int v6only; if (! peer->af_group[afi][safi]) return 0; @@ -5918,7 +6001,12 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, if (afi == AFI_IP && safi == SAFI_UNICAST) { if (peer->conf_if) - vty_out (vty, " neighbor %s interface%s", addr, VTY_NEWLINE); + { + if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) + vty_out (vty, " neighbor %s interface v6only %s", addr, VTY_NEWLINE); + else + vty_out (vty, " neighbor %s interface%s", addr, VTY_NEWLINE); + } /* remote-as. */ if (! peer_group_active (peer)) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0c0c6a6f62..4bbfbf7192 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -614,6 +614,7 @@ struct peer #define PEER_FLAG_LONESOUL (1 << 12) #define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 13) /* dynamic neighbor */ #define PEER_FLAG_CAPABILITY_ENHE (1 << 14) /* Extended next-hop (rfc 5549)*/ +#define PEER_FLAG_IFPEER_V6ONLY (1 << 15) /* if-based peer is v6 only * /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; @@ -677,6 +678,7 @@ struct peer #define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */ #define PEER_CONFIG_CONNECT (1 << 2) /* connect */ #define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */ + u_int32_t weight; u_int32_t holdtime; u_int32_t keepalive; @@ -796,6 +798,7 @@ struct peer #define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */ #define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */ #define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */ +#define PEER_DOWN_V6ONLY_CHANGE 23 /* if-based peering v6only toggled */ unsigned long last_reset_cause_size; u_char last_reset_cause[BGP_MAX_PACKET_SIZE]; @@ -1111,7 +1114,7 @@ extern struct bgp *bgp_lookup_by_name (const char *); extern struct peer *peer_lookup (struct bgp *, union sockunion *); extern struct peer *peer_lookup_by_conf_if (struct bgp *, const char *); extern struct peer *peer_conf_interface_get(struct bgp *, const char *, afi_t, - safi_t); + safi_t, int v6only); extern void bgp_peer_conf_if_to_su_update (struct peer *); extern int peer_group_listen_range_del(struct peer_group *, struct prefix *); extern struct peer_group *peer_group_lookup (struct bgp *, const char *); -- 2.39.5