From: James Li <[email protected]>

Allow ospf to use unnumbered links by utilizing the loopback interface IP
address.

Example Config:

interface lo:1
  address 10.2.1.3/32

int swp1
  ip ospf network point-to-point

int swp2
  ip ospf network point-to-point

router ospf
  ospf router-id 10.2.1.3
  network 10.2.1.3/32 area 0.0.0.0

Signed-off-by: James Li <[email protected]>
Signed-off-by: Dinesh Dutt <[email protected]>
Reviewed-by: JR Rivers <[email protected]>
---
 lib/if.c               |   30 +++++++++++++++++++++++++
 lib/if.h               |   10 ++++++++-
 lib/zebra.h            |    1 +
 ospfd/ospf_interface.c |   13 ++++++++---
 ospfd/ospf_lsa.c       |   39 ++++++++++++++++++++++----------
 ospfd/ospf_route.c     |    4 ++++
 ospfd/ospf_route.h     |    1 +
 ospfd/ospf_vty.c       |   55 +++++++++++++++++++++++++--------------------
 ospfd/ospf_zebra.c     |   40 +++++++++++++++++++++++++++++++--
 zebra/connected.c      |   58 ++++++++++++++++++++++++++++++++++++++++++++++--
 zebra/connected.h      |    3 +++
 zebra/interface.c      |    4 ++++
 12 files changed, 214 insertions(+), 44 deletions(-)

diff --git a/lib/if.c b/lib/if.c
index 4d4b656..2d6c9af 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -355,6 +355,36 @@ if_lookup_address (struct in_addr src)
   return if_lookup_address_vrf (src, VRF_DEFAULT);
 }
 
+/* Lookup anchor interface by IPv4 address. */
+struct connected *
+if_anchor_lookup_by_address (struct in_addr src)
+{
+  struct listnode *node;
+  struct listnode *cnode;
+  struct interface *ifp;
+  struct prefix *p;
+  struct connected *c;
+
+  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+    {
+      for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+        {
+          if (CHECK_FLAG(c->flags, ZEBRA_IFA_UNNUMBERED) ||
+              !CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+            continue;
+
+          p = c->address;
+
+          if (p && p->family == AF_INET)
+            {
+              if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
+                return c;
+            }
+        }
+    }
+  return NULL;
+}
+
 /* Lookup interface by prefix */
 struct interface *
 if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
diff --git a/lib/if.h b/lib/if.h
index ad85dca..18b40c0 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -90,7 +90,7 @@ struct interface
 #define ZEBRA_INTERFACE_ACTIVE     (1 << 0)
 #define ZEBRA_INTERFACE_SUB        (1 << 1)
 #define ZEBRA_INTERFACE_LINKDETECTION (1 << 2)
-  
+
   /* Interface flags. */
   uint64_t flags;
 
@@ -169,6 +169,7 @@ struct connected
   u_char flags;
 #define ZEBRA_IFA_SECONDARY    (1 << 0)
 #define ZEBRA_IFA_PEER         (1 << 1)
+#define ZEBRA_IFA_UNNUMBERED   (1 << 2)
   /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if
      a peer address has been configured.  If this flag is set,
      the destination field must contain the peer address.  
@@ -183,6 +184,12 @@ struct connected
      Note: destination may be NULL if ZEBRA_IFA_PEER is not set. */
   struct prefix *destination;
 
+  /* A list of unnumbered IFCs borrowing the address from me */
+  struct list *unnumbered;
+
+  /* Pointer to the anchor IFC if I'm unnumbered */
+  struct connected *anchor;
+
   /* Label for Linux 2.2.X and upper. */
   char *label;
 };
@@ -248,6 +255,7 @@ extern struct interface *if_lookup_by_index (unsigned int);
 extern struct interface *if_lookup_exact_address (struct in_addr);
 extern struct interface *if_lookup_address (struct in_addr);
 extern struct interface *if_lookup_prefix (struct prefix *prefix);
+extern struct connected *if_anchor_lookup_by_address (struct in_addr src);
 
 extern struct interface *if_create_vrf (const char *name, int namelen,
                                 vrf_id_t vrf_id);
diff --git a/lib/zebra.h b/lib/zebra.h
index 0bc5309..1322a80 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -465,6 +465,7 @@ extern const char *zserv_command_string (unsigned int 
command);
 #define ZEBRA_FLAG_CHANGED            0x20
 #define ZEBRA_FLAG_STATIC             0x40
 #define ZEBRA_FLAG_REJECT             0x80
+#define ZEBRA_FLAG_SCOPE_LINK         0x100
 
 /* Zebra nexthop flags. */
 #define ZEBRA_NEXTHOP_IFINDEX            1
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 07c3fe3..24f795c 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -353,7 +353,12 @@ ospf_if_is_configured (struct ospf *ospf, struct in_addr 
*address)
   for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
     if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
       {
-        if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+        if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+          {
+            if (htonl(oi->ifp->ifindex) == address->s_addr)
+              return oi;
+          }
+        else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
          {
            /* special leniency: match if addr is anywhere on peer subnet */
            if (prefix_match(CONNECTED_PREFIX(oi->connected),
@@ -477,8 +482,10 @@ ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr 
src,
       if (if_is_loopback (oi->ifp))
         continue;
 
-      if (prefix_match (CONNECTED_PREFIX(oi->connected),
-                       (struct prefix *) &addr))
+      if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+        match = oi;
+      else if (prefix_match (CONNECTED_PREFIX(oi->connected),
+                             (struct prefix *) &addr))
        {
          if ( (match == NULL) || 
               (match->address->prefixlen < oi->address->prefixlen)
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index f032601..79bf8b8 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -532,7 +532,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface 
*oi)
 {
   int links = 0;
   struct ospf_neighbor *nbr;
-  struct in_addr id, mask;
+  struct in_addr id, mask, data;
   u_int16_t cost = ospf_link_cost (oi);
 
   if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
@@ -541,19 +541,34 @@ lsa_link_ptop_set (struct stream *s, struct 
ospf_interface *oi)
   if ((nbr = ospf_nbr_lookup_ptop (oi)))
     if (nbr->state == NSM_Full)
       {
-       /* For unnumbered point-to-point networks, the Link Data field
-          should specify the interface's MIB-II ifIndex value. */
-       links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
-                               LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+        if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+          {
+            /* For unnumbered point-to-point networks, the Link Data field
+               should specify the interface's MIB-II ifIndex value. */
+            data.s_addr = htonl(oi->ifp->ifindex);
+            links += link_info_set (s, nbr->router_id, data,
+                                    LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+          }
+        else
+          {
+            links += link_info_set (s, nbr->router_id,
+                                    oi->address->u.prefix4,
+                                    LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+          }
       }
 
-  /* Regardless of the state of the neighboring router, we must
-     add a Type 3 link (stub network).
-     N.B. Options 1 & 2 share basically the same logic. */
-  masklen2ip (oi->address->prefixlen, &mask);
-  id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr;
-  links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
-                         oi->output_cost);
+  /* no need for a stub link for unnumbered interfaces */
+  if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+    {
+      /* Regardless of the state of the neighboring router, we must
+         add a Type 3 link (stub network).
+         N.B. Options 1 & 2 share basically the same logic. */
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & 
mask.s_addr;
+      links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+                              oi->output_cost);
+    }
+
   return links;
 }
 
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index eb7829a..7efba7a 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -611,6 +611,8 @@ ospf_intra_add_stub (struct route_table *rt, struct 
router_lsa_link *link,
          path = ospf_path_new ();
          path->nexthop.s_addr = 0;
          path->ifindex = oi->ifp->ifindex;
+          if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+            path->unnumbered = 1;
          listnode_add (or->paths, path);
        }
       else
@@ -783,6 +785,8 @@ ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
              path = ospf_path_new ();
              path->nexthop = nexthop->router;
              path->ifindex = nexthop->oi->ifp->ifindex;
+              if (CHECK_FLAG(nexthop->oi->connected->flags, 
ZEBRA_IFA_UNNUMBERED))
+                path->unnumbered = 1;
              listnode_add (to->paths, path);
            }
        }
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index 6c202b0..4de3a3d 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -40,6 +40,7 @@ struct ospf_path
   struct in_addr nexthop;
   struct in_addr adv_router;
   unsigned int ifindex;
+  unsigned char unnumbered;
 };
 
 /* Below is the structure linked to every
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 9d04892..1a96de7 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2849,30 +2849,37 @@ show_ip_ospf_interface_sub (struct vty *vty, struct 
ospf *ospf,
       if (oi == NULL)
        continue;
       
-      /* Show OSPF interface information. */
-      vty_out (vty, "  Internet Address %s/%d,",
-              inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
-
-      if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+      if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
         {
-          struct in_addr *dest;
-          const char *dstr;
-          
-         if (CONNECTED_PEER(oi->connected)
-             || oi->type == OSPF_IFTYPE_VIRTUALLINK)
-            dstr = "Peer";
-          else
-            dstr = "Broadcast";
-          
-          /* For Vlinks, showing the peer address is probably more
-           * informative than the local interface that is being used
-           */
-          if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-            dest = &oi->vl_data->peer_addr;
-          else
-            dest = &oi->connected->destination->u.prefix4;
-          
-         vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
+          vty_out (vty, "  This interface is UNNUMBERED,");
+        }
+      else
+        {
+          /* Show OSPF interface information. */
+          vty_out (vty, "  Internet Address %s/%d,",
+                   inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
+
+          if (oi->connected->destination || oi->type == 
OSPF_IFTYPE_VIRTUALLINK)
+            {
+              struct in_addr *dest;
+              const char *dstr;
+
+              if (CONNECTED_PEER(oi->connected)
+                  || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+                dstr = "Peer";
+              else
+                dstr = "Broadcast";
+
+              /* For Vlinks, showing the peer address is probably more
+               * informative than the local interface that is being used
+               */
+              if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+                dest = &oi->vl_data->peer_addr;
+              else
+                dest = &oi->connected->destination->u.prefix4;
+
+              vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
+            }
         }
 
       vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area),
@@ -2924,7 +2931,7 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf 
*ospf,
                       inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
            }
        }
-      
+
       /* Next network-LSA sequence number we'll use, if we're elected DR */
       if (oi->params && ntohl (oi->params->network_lsa_seqnum)
                           != OSPF_INITIAL_SEQUENCE_NUMBER)
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 2704100..b234c27 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -373,6 +373,40 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route 
*or)
       /* Nexthop, ifindex, distance and metric information. */
       for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
         {
+#ifdef HAVE_NETLINK
+          if (path->unnumbered)
+            {
+              stream_putc (s, ZEBRA_NEXTHOP_IPV4_ONLINK);
+              stream_put_in_addr (s, &path->nexthop);
+              if (path->ifindex)
+                stream_putl (s, path->ifindex);
+              else
+                stream_putl (s, 0);
+            }
+          else
+            {
+             if (path->nexthop.s_addr != INADDR_ANY &&
+                 path->ifindex != 0)
+               {
+                 stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX);
+                 stream_put_in_addr (s, &path->nexthop);
+                 stream_putl (s, path->ifindex);
+               }
+             else if (path->nexthop.s_addr != INADDR_ANY)
+                {
+                  stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+                  stream_put_in_addr (s, &path->nexthop);
+                }
+              else
+                {
+                  stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+                  if (path->ifindex)
+                    stream_putl (s, path->ifindex);
+                  else
+                    stream_putl (s, 0);
+                }
+            }
+#else  /* HAVE_NETLINK */
           if (path->nexthop.s_addr != INADDR_ANY &&
              path->ifindex != 0)
             {
@@ -393,16 +427,18 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route 
*or)
               else
                 stream_putl (s, 0);
             }
+#endif /* HAVE_NETLINK */
 
           if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
             {
              char buf[2][INET_ADDRSTRLEN];
-             zlog_debug("Zebra: Route add %s/%d nexthop %s",
+             zlog_debug("Zebra: Route add %s/%d nexthop %s, ifindex=%d",
                         inet_ntop(AF_INET, &p->prefix,
                                   buf[0], sizeof(buf[0])),
                         p->prefixlen,
                         inet_ntop(AF_INET, &path->nexthop,
-                                  buf[1], sizeof(buf[1])));
+                                  buf[1], sizeof(buf[1])),
+                        path->ifindex);
             }
         }
 
diff --git a/zebra/connected.c b/zebra/connected.c
index 244f291..0fe0915 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -77,7 +77,23 @@ connected_announce (struct interface *ifp, struct connected 
*ifc)
 {
   if (!ifc)
     return;
-  
+
+  if (ifc->address->family == AF_INET)
+    {
+      if ((ifc->anchor = if_anchor_lookup_by_address(ifc->address->u.prefix4)))
+      {
+        /* found an anchor, so I'm unnumbered */
+        SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
+        listnode_add (ifc->anchor->unnumbered, ifc);
+      }
+    else
+      {
+        /* I'm numbered */
+        UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
+        ifc->unnumbered = list_new();
+      }
+    }
+
   listnode_add (ifp->connected, ifc);
 
   /* Update interface address information to protocol daemon. */
@@ -313,6 +329,42 @@ connected_down_ipv4 (struct interface *ifp, struct 
connected *ifc)
   rib_update (ifp->vrf_id);
 }
 
+void
+connected_delete_ipv4_unnumbered (struct connected *ifc)
+{
+  struct connected *new_anchor, *iter;
+  struct listnode *node;
+
+  if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED))
+    {
+      listnode_delete (ifc->anchor->unnumbered, ifc);
+      ifc->anchor = NULL;
+    }
+  else /* I'm a numbered interface */
+    {
+      if (!list_isempty (ifc->unnumbered))
+        {
+          new_anchor = listgetdata (listhead (ifc->unnumbered));
+          new_anchor->unnumbered = ifc->unnumbered;
+          listnode_delete (new_anchor->unnumbered, new_anchor);
+          new_anchor->anchor = NULL;
+
+          /* new_anchor changed from unnumbered to numbered, notify clients */
+          zebra_interface_address_delete_update (new_anchor->ifp, new_anchor);
+          UNSET_FLAG (new_anchor->flags, ZEBRA_IFA_UNNUMBERED);
+          zebra_interface_address_add_update (new_anchor->ifp, new_anchor);
+
+          for (ALL_LIST_ELEMENTS_RO(new_anchor->unnumbered, node, iter))
+            iter->anchor = new_anchor;
+        }
+      else
+        {
+          list_free (ifc->unnumbered);
+          ifc->unnumbered = NULL;
+        }
+    }
+}
+
 /* Delete connected IPv4 route to the interface. */
 void
 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
@@ -329,7 +381,9 @@ connected_delete_ipv4 (struct interface *ifp, int flags, 
struct in_addr *addr,
   ifc = connected_check (ifp, (struct prefix *) &p);
   if (! ifc)
     return;
-    
+
+  connected_delete_ipv4_unnumbered (ifc);
+
   connected_withdraw (ifc);
 
   rib_update (ifp->vrf_id);
diff --git a/zebra/connected.h b/zebra/connected.h
index 9595ddb..5570944 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -35,6 +35,9 @@ extern void
 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
                       u_char prefixlen, struct in_addr *broad);
 
+extern void
+connected_delete_ipv4_unnumbered (struct connected *ifc);
+
 extern void connected_up_ipv4 (struct interface *, struct connected *);
 extern void connected_down_ipv4 (struct interface *, struct connected *);
 
diff --git a/zebra/interface.c b/zebra/interface.c
index 14c3e78..7fb1d67 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -471,6 +471,7 @@ if_delete_update (struct interface *ifp)
 
                  UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
                  UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+                  connected_delete_ipv4_unnumbered(ifc);
 
                  /* Remove from subnet chain. */
                  list_delete_node (addr_list, anode);
@@ -630,6 +631,9 @@ connected_dump_vty (struct vty *vty, struct connected 
*connected)
   if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
     vty_out (vty, " secondary");
 
+  if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED))
+    vty_out (vty, " unnumbered");
+
   if (connected->label)
     vty_out (vty, " %s", connected->label);
 
-- 
1.7.10.4


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

Reply via email to