]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd-interface-ipv4-cmd.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 22 Jul 2015 19:35:37 +0000 (12:35 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 22 Jul 2015 19:35:37 +0000 (12:35 -0700)
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 <ddutt@cumulusnetworks.com>
Reviewed-By: Vivek Venkataram <vivek@cumulusnetworks.com>
bgpd/bgp_nexthop.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h

index 40b719fe31ec851e03cc7d1a75878fe08f1da5cf..658a4b1fd5e6b935c7d894f98f710ddd3055187c 100644 (file)
@@ -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)
index 96ebf4f58ce9b5c76e0d5e31c0a89631d9fe98ad..c69ef0831a25f7d097daa70554068cb737c4737a 100644 (file)
@@ -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
index 380a45559d1758cbe524991d9b2b9a02e3bfcf11..5a633ed60f9c21b5037f0ce894e740b6ee3fda56 100644 (file)
@@ -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))
index 0c0c6a6f62b5fd7800bd81fc07f4ea7ea3c5ea0e..4bbfbf7192b9c5fb4df324c05b31a9c82e973ae4 100644 (file)
@@ -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 *);