[quagga-dev 10830] [PATCH 3/4] ospfd: ospfd-unnumbered-interface-support.patch

Dinesh G Dutt ddutt at cumulusnetworks.com
Thu Oct 24 05:06:50 BST 2013


OSPFv2: Support for Unnumbered interface.

Unnumbered interface support for OSPFv2.

Signed-off-by: James Li <jli at cumulusnetworks.com>
Reviewed-by: Dinesh Dutt <ddutt at cumulusnetworks.com>
---
 lib/if.c               |   29 +++++++++++++++++++++++++
 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     |   45 +++++++++++++++++++++++++++++++++++++++
 zebra/connected.c      |   51 ++++++++++++++++++++++++++++++++++++++++++++-
 zebra/connected.h      |    3 +++
 zebra/interface.c      |   18 ++++++++++++++++
 12 files changed, 228 insertions(+), 41 deletions(-)

diff --git a/lib/if.c b/lib/if.c
index 798d8a6..406102a 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -308,6 +308,35 @@ if_lookup_address (struct in_addr src)
   return match;
 }
 
+/* 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))
+            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 (struct prefix *prefix)
diff --git a/lib/if.h b/lib/if.h
index cb44511..cd2b979 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;
 
@@ -165,6 +165,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.  
@@ -179,6 +180,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;
 };
@@ -244,6 +251,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);
 
 /* These 2 functions are to be used when the ifname argument is terminated
    by a '\0' character: */
diff --git a/lib/zebra.h b/lib/zebra.h
index 7583a03..d4e6f19 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -477,6 +477,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 47ca790..dd13562 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 cb836e1..034f547 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -458,7 +458,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))
@@ -467,19 +467,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 a6a7db4..dcd7129 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2872,30 +2872,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),
@@ -2947,7 +2954,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 34a3b2a..701370b 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -334,6 +334,9 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
   struct stream *s;
   struct ospf_path *path;
   struct listnode *node;
+#ifdef HAVE_NETLINK
+  int ol_cnt = 0, not_ol_cnt = 0;
+#endif /* HAVE_NETLINK */
 
   if (zclient->redist[ZEBRA_ROUTE_OSPF])
     {
@@ -366,11 +369,52 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
       stream_write (s, (u_char *) & p->prefix, psize);
 
       /* Nexthop count. */
+#ifdef HAVE_NETLINK
+      for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
+        {
+            if (path->unnumbered)
+              ol_cnt++;
+            else
+              not_ol_cnt++;
+        }
+      stream_putc (s, ol_cnt*2 + not_ol_cnt);
+#else  /* HAVE_NETLINK */
       stream_putc (s, or->paths->count);
+#endif /* HAVE_NETLINK */
 
       /* Nexthop, ifindex, distance and metric information. */
       for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
         {
+#ifdef HAVE_NETLINK
+          if (path->unnumbered)
+            {
+              SET_FLAG (message, ZAPI_MESSAGE_ONLINK);
+              stream_putc (s, ZEBRA_NEXTHOP_IPV4_ONLINK);
+              stream_put_in_addr (s, &path->nexthop);
+
+              stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+              if (path->ifindex)
+                stream_putl (s, path->ifindex);
+              else
+                stream_putl (s, 0);
+            }
+          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)
             {
@@ -391,6 +435,7 @@ 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))
             {
diff --git a/zebra/connected.c b/zebra/connected.c
index 05538c5..ae967cd 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -211,6 +211,19 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
   ifc->ifp = ifp;
   ifc->flags = flags;
 
+  if (ifc->anchor = if_anchor_lookup_by_address(*addr))
+    {
+      /* 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();
+    }
+
   /* Allocate new connected address. */
   p = prefix_ipv4_new ();
   p->family = AF_INET;
@@ -305,6 +318,40 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
   rib_update ();
 }
 
+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);
+    }
+  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 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,
@@ -321,7 +368,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();
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 8f8ffdc..87fdee1 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -607,6 +607,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);
 
@@ -1226,6 +1229,19 @@ ip_address_install (struct vty *vty, struct interface *ifp,
       if (label)
 	ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
 
+      if (ifc->anchor = if_anchor_lookup_by_address(cp.prefix))
+        {
+          /* 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();
+        }
+
       /* Add to linked list. */
       listnode_add (ifp->connected, ifc);
     }
@@ -1332,6 +1348,8 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
   /* Remove connected route. */
   connected_down_ipv4 (ifp, ifc);
 
+  connected_delete_ipv4_unnumbered (ifc);
+
   /* Redistribute this information. */
   zebra_interface_address_delete_update (ifp, ifc);
 





More information about the Quagga-dev mailing list