[quagga-users 12340] Re: Problem with conditional default-information originate in ospfd

Unik unik at compot.ru
Sun Jun 12 18:44:13 IST 2011


Hello.

As a followup to my previous message, after some 2 days of research and
trying, I came up with a patch to do this:

=== cut ===

default-information originate always route-map SOME-MAP

route-map SOME-MAP permit 10
 match ip address prefix-list PL-CHECK-HEALTH

route-map SOME-MAP deny 20

=== cut ===

It has several limitations in current form:

1. No work has been done for IPv6.
2. Only prefix-list matching is supported for now.

Patch is rather intrusive:

1. It moves struct prefix_list_entry definition from private .c file to
public .h file.

2. It adds new zserv message type (lookup in RIB by prefix). I tried to
use existing types, but to no avail (all existing lookups ignore eBGP
routes).

3. It adds new route-map object type (RMAP_OSPF_DEFAULT). Currently only
prefix list matching is implemented for this type.

So, here is the patch (on top of 0.99.18), let the flames/review
commence.

=== === ===

diff -Naur quagga-0.99.18-orig/lib/plist.c quagga-0.99.18/lib/plist.c
--- quagga-0.99.18-orig/lib/plist.c	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/lib/plist.c	2011-06-11 09:23:02.395467744 +0400
@@ -30,26 +30,6 @@
 #include "stream.h"
 #include "log.h"
 
-/* Each prefix-list's entry. */
-struct prefix_list_entry
-{
-  int seq;
-
-  int le;
-  int ge;
-
-  enum prefix_list_type type;
-
-  int any;
-  struct prefix prefix;
-
-  unsigned long refcnt;
-  unsigned long hitcnt;
-
-  struct prefix_list_entry *next;
-  struct prefix_list_entry *prev;
-};
-
 /* List of struct prefix_list. */
 struct prefix_list_list
 {
diff -Naur quagga-0.99.18-orig/lib/plist.h quagga-0.99.18/lib/plist.h
--- quagga-0.99.18-orig/lib/plist.h	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/lib/plist.h	2011-06-11 09:22:28.572134635 +0400
@@ -56,6 +56,26 @@
   struct prefix_list *prev;
 };
 
+/* Each prefix-list's entry. */
+struct prefix_list_entry
+{
+  int seq;
+
+  int le;
+  int ge;
+
+  enum prefix_list_type type;
+
+  int any;
+  struct prefix prefix;
+
+  unsigned long refcnt;
+  unsigned long hitcnt;
+
+  struct prefix_list_entry *next;
+  struct prefix_list_entry *prev;
+};
+
 struct orf_prefix
 {
   u_int32_t seq;
diff -Naur quagga-0.99.18-orig/lib/routemap.h quagga-0.99.18/lib/routemap.h
--- quagga-0.99.18-orig/lib/routemap.h	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/lib/routemap.h	2011-06-11 08:19:17.622159706 +0400
@@ -46,7 +46,8 @@
   RMAP_OSPF,
   RMAP_OSPF6,
   RMAP_BGP,
-  RMAP_ZEBRA
+  RMAP_ZEBRA,
+  RMAP_OSPF_DEFAULT
 } route_map_object_t;
 
 typedef enum
diff -Naur quagga-0.99.18-orig/lib/zebra.h quagga-0.99.18/lib/zebra.h
--- quagga-0.99.18-orig/lib/zebra.h	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/lib/zebra.h	2011-06-12 06:44:49.426606713 +0400
@@ -421,7 +421,9 @@
 #define ZEBRA_ROUTER_ID_ADD               20
 #define ZEBRA_ROUTER_ID_DELETE            21
 #define ZEBRA_ROUTER_ID_UPDATE            22
-#define ZEBRA_MESSAGE_MAX                 23
+#define ZEBRA_IPV4_RIB_LOOKUP             23
+#define ZEBRA_IPV6_RIB_LOOKUP             24
+#define ZEBRA_MESSAGE_MAX                 25
 
 /* Marker value used in new Zserv, in the byte location corresponding
  * the command value in the old zserv header. To allow old and new
diff -Naur quagga-0.99.18-orig/ospfd/ospf_routemap.c quagga-0.99.18/ospfd/ospf_routemap.c
--- quagga-0.99.18-orig/ospfd/ospf_routemap.c	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/ospfd/ospf_routemap.c	2011-06-12 08:04:41.326574811 +0400
@@ -331,6 +331,35 @@
   route_match_ip_address_free
 };
 
+/* as following, but in default-originate route-map context */
+static route_map_result_t
+route_default_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+
+  if (type == RMAP_OSPF_DEFAULT)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      if (plist->count == 0)
+        return RMAP_MATCH;
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+      {
+        pentry->refcnt++;
+        if (ospf_zebra_lookup_query (&(pentry->prefix.u.prefix4)))
+        {
+          pentry->hitcnt++;
+          return RMAP_MATCH;
+        }
+      }
+    }
+  return RMAP_NOMATCH;
+}
+
 /* `match ip address prefix-list PREFIX_LIST' */
 static route_map_result_t
 route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
@@ -347,6 +376,9 @@
       return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
               RMAP_NOMATCH : RMAP_MATCH);
     }
+  else if (type == RMAP_OSPF_DEFAULT)
+    return route_default_match_ip_address_prefix_list (rule, prefix, type,
+                                                       object);
   return RMAP_NOMATCH;
 }
 
diff -Naur quagga-0.99.18-orig/ospfd/ospf_zebra.c quagga-0.99.18/ospfd/ospf_zebra.c
--- quagga-0.99.18-orig/ospfd/ospf_zebra.c	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/ospfd/ospf_zebra.c	2011-06-12 08:03:58.646575097 +0400
@@ -51,6 +51,7 @@
 
 /* Zebra structure to hold current status. */
 struct zclient *zclient = NULL;
+struct zclient *zlookup = NULL;
 
 /* For registering threads. */
 extern struct thread_master *master;
@@ -473,6 +474,92 @@
     }
 }
 
+int
+ospf_zebra_lookup_read ()
+{
+  struct stream *s;
+  uint16_t length;
+  u_char marker;
+  u_char version;
+  uint16_t command;
+  int nbytes;
+  struct in_addr raddr;
+  uint32_t metric;
+  u_char nexthop_num;
+
+  zlog_info("ospf_zebra_lookup_read: phase 1");
+
+  s = zlookup->ibuf;
+  stream_reset (s);
+
+  nbytes = stream_read (s, zlookup->sock, 2);
+  length = stream_getw (s);
+
+  nbytes = stream_read (s, zlookup->sock, length - 2);
+  marker = stream_getc (s);
+  version = stream_getc (s);
+  
+  if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER)
+    {
+      zlog_err("%s: socket %d version mismatch, marker %d, version %d",
+               __func__, zlookup->sock, marker, version);
+      return 0;
+    }
+    
+  command = stream_getw (s);
+ 
+  raddr.s_addr = stream_get_ipv4 (s);
+  metric = stream_getl (s);
+  nexthop_num = stream_getc (s);
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+  {
+    zlog_debug("ospf_zebra_lookup_read: got %s", inet_ntoa(raddr));
+    zlog_debug("ospf_zebra_lookup_read: got metric %u", metric);
+    zlog_debug("ospf_zebra_lookup_read: got nexthop_num %u", nexthop_num);
+  }
+
+  return ( (metric > 0) || (nexthop_num > 0) ? 1 : 0 );
+}
+
+int
+ospf_zebra_lookup_query (struct prefix_ipv4 *p)
+{
+  int ret;
+  struct stream *s;
+
+  /* Check socket. */
+  if (zlookup->sock < 0)
+    return 0;
+
+  s = zlookup->obuf;
+  stream_reset (s);
+  zclient_create_header (s, ZEBRA_IPV4_RIB_LOOKUP);
+
+  stream_putc (s, p->prefixlen);
+  stream_put_in_addr (s, &p->prefix);
+  
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  ret = writen (zlookup->sock, s->data, stream_get_endp (s));
+  if (ret < 0)
+    {
+      zlog_err ("can't write to zlookup->sock");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return 0;
+    }
+  if (ret == 0)
+    {
+      zlog_err ("zlookup->sock connection closed");
+      close (zlookup->sock);
+      zlookup->sock = -1;
+      return 0;
+    }
+
+  return ospf_zebra_lookup_read ();
+}
+
 void
 ospf_zebra_add_discard (struct prefix_ipv4 *p)
 {
@@ -733,7 +820,9 @@
       int ret;
 
       ret = route_map_apply (ROUTEMAP (ospf, type), (struct prefix *) p,
-                             RMAP_OSPF, ei);
+                             (DEFAULT_ROUTE_TYPE (type) ? RMAP_OSPF_DEFAULT :
+                                                          RMAP_OSPF),
+                             ei);
 
       if (ret == RMAP_DENYMATCH)
         {
@@ -1257,6 +1346,29 @@
   return 0;
 }
 
+/* Connect to zebra for nexthop lookup. */
+static int
+zlookup_connect (struct thread *t)
+{
+  struct zclient *zlookup;
+
+  zlookup = THREAD_ARG (t);
+  zlookup->t_connect = NULL;
+
+  if (zlookup->sock != -1)
+    return 0;
+
+#ifdef HAVE_TCP_ZEBRA
+  zlookup->sock = zclient_socket ();
+#else
+  zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+  if (zlookup->sock < 0)
+    return -1;
+
+  return 0;
+}
+
 void
 ospf_zebra_init ()
 {
@@ -1273,6 +1385,10 @@
   zclient->ipv4_route_add = ospf_zebra_read_ipv4;
   zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
 
+  zlookup = zclient_new ();
+  zlookup->sock = -1;
+  zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0);
+
   access_list_add_hook (ospf_filter_update);
   access_list_delete_hook (ospf_filter_update);
   prefix_list_add_hook (ospf_prefix_list_update);
diff -Naur quagga-0.99.18-orig/ospfd/ospf_zebra.h quagga-0.99.18/ospfd/ospf_zebra.h
--- quagga-0.99.18-orig/ospfd/ospf_zebra.h	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/ospfd/ospf_zebra.h	2011-06-12 07:28:16.123256463 +0400
@@ -47,6 +47,8 @@
 extern void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *);
 extern void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *);
 
+extern int ospf_zebra_lookup_query (struct prefix_ipv4 *);
+
 extern void ospf_zebra_add_discard (struct prefix_ipv4 *);
 extern void ospf_zebra_delete_discard (struct prefix_ipv4 *);
 
diff -Naur quagga-0.99.18-orig/zebra/rib.h quagga-0.99.18/zebra/rib.h
--- quagga-0.99.18-orig/zebra/rib.h	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/zebra/rib.h	2011-06-12 07:08:01.483264114 +0400
@@ -260,6 +260,7 @@
 extern struct rib *rib_match_ipv4 (struct in_addr);
 
 extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *);
+extern struct rib *rib_lookup_any_ipv4 (struct prefix_ipv4 *);
 
 extern void rib_update (void);
 extern void rib_weed_tables (void);
@@ -286,6 +287,7 @@
 		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
 
 extern struct rib *rib_lookup_ipv6 (struct in6_addr *);
+extern struct rib *rib_lookup_any_ipv6 (struct in6_addr *);
 
 extern struct rib *rib_match_ipv6 (struct in6_addr *);
 
diff -Naur quagga-0.99.18-orig/zebra/zebra_rib.c quagga-0.99.18/zebra/zebra_rib.c
--- quagga-0.99.18-orig/zebra/zebra_rib.c	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/zebra/zebra_rib.c	2011-06-12 07:11:17.469929471 +0400
@@ -616,6 +616,52 @@
 }
 
 /*
+ * Same as rib_lookup_ipv4, except doesn't care if route is eBGP or not.
+ */
+struct rib *
+rib_lookup_any_ipv4 (struct prefix_ipv4 *p)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return 0;
+
+  rn = route_node_lookup (table, (struct prefix *) p);
+
+  /* No route for this prefix. */
+  if (! rn)
+    return NULL;
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+
+  for (match = rn->info; match; match = match->next)
+    {
+      if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
+	continue;
+      if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	break;
+    }
+
+  if (! match)
+    return NULL;
+
+  if (match->type == ZEBRA_ROUTE_CONNECT)
+    return match;
+  
+  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+    if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+      return match;
+
+  return NULL;
+}
+
+/*
  * This clone function, unlike its original rib_lookup_ipv4(), checks
  * if specified IPv4 route record (prefix/mask -> gate) exists in
  * the whole RIB and has ZEBRA_FLAG_SELECTED set.
diff -Naur quagga-0.99.18-orig/zebra/zserv.c quagga-0.99.18/zebra/zserv.c
--- quagga-0.99.18-orig/zebra/zserv.c	2011-03-21 12:43:52.000000000 +0300
+++ quagga-0.99.18/zebra/zserv.c	2011-06-12 07:26:57.903256548 +0400
@@ -596,6 +596,64 @@
 }
 
 static int
+zsend_ipv4_rib_lookup (struct zserv *client, struct prefix_ipv4 *p)
+{
+  struct stream *s;
+  struct rib *rib;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Lookup nexthop. */
+  rib = rib_lookup_any_ipv4 (p);
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  zserv_create_header (s, ZEBRA_IPV4_RIB_LOOKUP);
+  stream_put_in_addr (s, &p->prefix);
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = stream_get_endp(s);
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
+	      {
+	      case ZEBRA_NEXTHOP_IPV4:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		break;
+	      case ZEBRA_NEXTHOP_IFINDEX:
+	      case ZEBRA_NEXTHOP_IFNAME:
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      default:
+                /* do nothing */
+		break;
+	      }
+	    num++;
+	  }
+      stream_putc_at (s, nump, num);
+    }
+  else
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 0);
+    }
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+  
+  return zebra_server_send_message(client);
+}
+
+static int
 zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
 {
   struct stream *s;
@@ -881,6 +939,19 @@
   return 0;
 }
 
+/* Simple RIB lookup for IPv4. */
+static int
+zread_ipv4_rib_lookup (struct zserv *client, u_short length)
+{
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (client->ibuf);
+  p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
+
+  return zsend_ipv4_rib_lookup (client, &p);
+}
+
 /* Nexthop lookup for IPv4. */
 static int
 zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
@@ -1275,6 +1346,9 @@
     case ZEBRA_IPV4_NEXTHOP_LOOKUP:
       zread_ipv4_nexthop_lookup (client, length);
       break;
+    case ZEBRA_IPV4_RIB_LOOKUP:
+      zread_ipv4_rib_lookup (client, length);
+      break;
 #ifdef HAVE_IPV6
     case ZEBRA_IPV6_NEXTHOP_LOOKUP:
       zread_ipv6_nexthop_lookup (client, length);

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
URL: <http://lists.quagga.net/pipermail/quagga-users/attachments/20110612/dbb519e3/attachment.bin>


More information about the Quagga-users mailing list