]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/zclient.c
*: use an ifindex_t type, defined in lib/if.h, for ifindex values
[mirror_frr.git] / lib / zclient.c
index 512abc24d7675d2ef6e35f4406910b711d1d6c93..a28db083cbbfa9d44dd38e54f00151ac057286b0 100644 (file)
@@ -39,7 +39,7 @@ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
 /* Prototype for event manager. */
 static void zclient_event (enum event, struct zclient *);
 
-char *zclient_serv_path = NULL;
+const char *zclient_serv_path = NULL;
 
 /* This file local debug flag. */
 int zclient_debug = 0;
@@ -202,6 +202,7 @@ zclient_socket(void)
   ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
   if (ret < 0)
     {
+      zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno);
       close (sock);
       return -1;
     }
@@ -237,6 +238,7 @@ zclient_socket_un (const char *path)
   ret = connect (sock, (struct sockaddr *) &addr, len);
   if (ret < 0)
     {
+      zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno);
       close (sock);
       return -1;
     }
@@ -258,7 +260,7 @@ zclient_socket_connect (struct zclient *zclient)
 #ifdef HAVE_TCP_ZEBRA
   zclient->sock = zclient_socket ();
 #else
-  zclient->sock = zclient_socket_un (zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH);
+  zclient->sock = zclient_socket_un (zclient_serv_path_get());
 #endif
   return zclient->sock;
 }
@@ -332,6 +334,32 @@ zclient_create_header (struct stream *s, uint16_t command, vrf_id_t vrf_id)
   stream_putw (s, command);
 }
 
+int
+zclient_read_header (struct stream *s, int sock, u_int16_t *size, u_char *marker,
+                     u_char *version, vrf_id_t *vrf_id, u_int16_t *cmd)
+{
+  if (stream_read (s, sock, ZEBRA_HEADER_SIZE) != ZEBRA_HEADER_SIZE)
+    return -1;
+
+  *size = stream_getw (s) - ZEBRA_HEADER_SIZE;
+  *marker = stream_getc (s);
+  *version = stream_getc (s);
+  *vrf_id = stream_getw (s);
+  *cmd = stream_getw (s);
+
+  if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER)
+    {
+      zlog_err("%s: socket %d version mismatch, marker %d, version %d",
+               __func__, sock, *marker, *version);
+      return -1;
+    }
+
+  if (*size && stream_read (s, sock, *size) != *size)
+    return -1;
+
+  return 0;
+}
+
 /* Send simple Zebra message. */
 static int
 zebra_message_send (struct zclient *zclient, int command, vrf_id_t vrf_id)
@@ -369,9 +397,9 @@ zebra_hello_send (struct zclient *zclient)
   return 0;
 }
 
-/* Send requests to zebra daemon for the information in a VRF. */
+/* Send register requests to zebra daemon for the information in a VRF. */
 void
-zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id)
+zclient_send_reg_requests (struct zclient *zclient, vrf_id_t vrf_id)
 {
   int i;
   afi_t afi;
@@ -385,7 +413,7 @@ zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id)
     return;
 
   if (zclient_debug)
-    zlog_debug ("%s: send messages for VRF %u", __func__, vrf_id);
+    zlog_debug ("%s: send register messages for VRF %u", __func__, vrf_id);
 
   /* We need router-id information. */
   zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD, vrf_id);
@@ -424,6 +452,93 @@ zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id)
     zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD, vrf_id);
 }
 
+/* Send unregister requests to zebra daemon for the information in a VRF. */
+void
+zclient_send_dereg_requests (struct zclient *zclient, vrf_id_t vrf_id)
+{
+  int i;
+  afi_t afi;
+
+  /* zclient is disabled. */
+  if (! zclient->enable)
+    return;
+
+  /* If not connected to the zebra yet. */
+  if (zclient->sock < 0)
+    return;
+
+  if (zclient_debug)
+    zlog_debug ("%s: send deregister messages for VRF %u", __func__, vrf_id);
+
+  /* We need router-id information. */
+  zebra_message_send (zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id);
+
+  /* We need interface information. */
+  zebra_message_send (zclient, ZEBRA_INTERFACE_DELETE, vrf_id);
+
+  /* Set unwanted redistribute route. */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    vrf_bitmap_set (zclient->redist[afi][zclient->redist_default], vrf_id);
+
+  /* Flush all redistribute request. */
+  if (vrf_id == VRF_DEFAULT)
+    for (afi = AFI_IP; afi < AFI_MAX; afi++)
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+        if (zclient->mi_redist[afi][i].enabled)
+          {
+            struct listnode *node;
+            u_short *id;
+
+            for (ALL_LIST_ELEMENTS_RO(zclient->mi_redist[afi][i].instances, node, id))
+              if (!(i == zclient->redist_default && *id == zclient->instance))
+                zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, i,
+                                         *id, VRF_DEFAULT);
+          }
+
+  /* Flush all redistribute request. */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+      if (i != zclient->redist_default &&
+          vrf_bitmap_check (zclient->redist[afi][i], vrf_id))
+        zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, i, 0, vrf_id);
+
+  /* If default information is needed. */
+  if (vrf_bitmap_check (zclient->default_information, VRF_DEFAULT))
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, vrf_id);
+}
+
+/* Send request to zebra daemon to start or stop RA. */
+void
+zclient_send_interface_radv_req (struct zclient *zclient, vrf_id_t vrf_id,
+                                 struct interface *ifp, int enable, int ra_interval)
+{
+  struct stream *s;
+
+  /* zclient is disabled. */
+  if (!zclient->enable)
+    return;
+
+  /* If not connected to the zebra yet. */
+  if (zclient->sock < 0)
+    return;
+
+  /* Form and send message. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  if (enable)
+    zclient_create_header (s, ZEBRA_INTERFACE_ENABLE_RADV, vrf_id);
+  else
+    zclient_create_header (s, ZEBRA_INTERFACE_DISABLE_RADV, vrf_id);
+
+  stream_putl (s, ifp->ifindex);
+  stream_putl (s, ra_interval);
+
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  zclient_send_message(zclient);
+}
+
 /* Make connection to zebra daemon. */
 int
 zclient_start (struct zclient *zclient)
@@ -443,11 +558,23 @@ zclient_start (struct zclient *zclient)
   if (zclient->t_connect)
     return 0;
 
-  if (zclient_socket_connect(zclient) < 0)
+  /*
+   * If we fail to connect to the socket on initialization,
+   * Let's wait a second and see if we can reconnect.
+   * Cause if we don't connect, we never attempt to
+   * reconnect.  On startup if zebra is slow we
+   * can get into this situation.
+   */
+  while (zclient_socket_connect(zclient) < 0 && zclient->fail < 5)
     {
       if (zclient_debug)
        zlog_debug ("zclient connection fail");
       zclient->fail++;
+      sleep (1);
+    }
+
+  if (zclient->sock < 0)
+    {
       zclient_event (ZCLIENT_CONNECT, zclient);
       return -1;
     }
@@ -850,6 +977,40 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid)
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
+static void
+zclient_vrf_add (struct zclient *zclient, vrf_id_t vrf_id)
+{
+  struct vrf *vrf;
+  char vrfname_tmp[VRF_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (vrfname_tmp, zclient->ibuf, VRF_NAMSIZ);
+
+  /* Lookup/create vrf by vrf_id. */
+  vrf = vrf_get (vrf_id, vrfname_tmp);
+
+  vrf_enable (vrf);
+}
+
+static void
+zclient_vrf_delete (struct zclient *zclient, vrf_id_t vrf_id)
+{
+  struct vrf *vrf;
+
+  /* Lookup vrf by vrf_id. */
+  vrf = vrf_lookup (vrf_id);
+
+  /*
+   * If a routing protocol doesn't know about a
+   * vrf that is about to be deleted.  There is
+   * no point in attempting to delete it.
+   */
+  if (!vrf)
+    return;
+
+  vrf_delete (vrf);
+}
+
 struct interface *
 zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id)
 {
@@ -862,7 +1023,7 @@ zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id)
   /* Lookup/create interface by name. */
   ifp = if_get_by_name_len_vrf (ifname_tmp,
                                 strnlen (ifname_tmp, INTERFACE_NAMSIZ),
-                                vrf_id);
+                                vrf_id, 0);
 
   zebra_interface_if_set_value (s, ifp);
 
@@ -889,10 +1050,12 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id)
   ifp = if_lookup_by_name_len_vrf (ifname_tmp,
                                    strnlen (ifname_tmp, INTERFACE_NAMSIZ),
                                    vrf_id);
-
-  /* If such interface does not exist, indicate an error */
-  if (! ifp)
-     return NULL;
+  if (ifp == NULL)
+    {
+      zlog_warn ("INTERFACE_STATE: Cannot find IF %s in VRF %d",
+                 ifname_tmp, vrf_id);
+      return NULL;
+    }
 
   zebra_interface_if_set_value (s, ifp);
 
@@ -951,7 +1114,7 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
 #else
   ifp->hw_addr_len = stream_getl (s);
   if (ifp->hw_addr_len)
-    stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
+    stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
 #endif /* HAVE_STRUCT_SOCKADDR_DL */
 }
 
@@ -970,7 +1133,7 @@ memconstant(const void *s, int c, size_t n)
 struct connected *
 zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
 {
-  unsigned int ifindex;
+  ifindex_t ifindex;
   struct interface *ifp;
   struct connected *ifc;
   struct prefix p, d;
@@ -988,10 +1151,9 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
   if (ifp == NULL)
     {
-      zlog_warn ("zebra_interface_address_read(%s): "
-                 "Can't find interface by ifindex: %d ",
-                 (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"),
-                 ifindex);
+      zlog_warn ("INTERFACE_ADDRESS_%s: Cannot find IF %u in VRF %d",
+                 (type == ZEBRA_INTERFACE_ADDRESS_ADD) ? "ADD" : "DEL",
+                 ifindex, vrf_id);
       return NULL;
     }
 
@@ -1011,10 +1173,14 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
 
   if (type == ZEBRA_INTERFACE_ADDRESS_ADD) 
     {
-       /* N.B. NULL destination pointers are encoded as all zeroes */
-       ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ?
-                                             NULL : &d));
-       if (ifc != NULL)
+      ifc = connected_lookup_prefix_exact (ifp, &p);
+      if (!ifc)
+        {
+          /* N.B. NULL destination pointers are encoded as all zeroes */
+          ifc = connected_add_by_prefix(ifp, &p, (memconstant(&d.u.prefix,0,plen) ?
+                                                NULL : &d));
+        }
+       if (ifc)
         {
           ifc->flags = ifc_flags;
           if (ifc->destination)
@@ -1022,11 +1188,11 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
           else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
             {
               /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */
-              char buf[BUFSIZ];
-              prefix2str (ifc->address, buf, sizeof(buf));
+              char buf[PREFIX_STRLEN];
               zlog_warn("warning: interface %s address %s "
                    "with peer flag set, but no peer address!",
-                   ifp->name, buf);
+                   ifp->name,
+                   prefix2str (ifc->address, buf, sizeof buf));
               UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
             }
         }
@@ -1076,13 +1242,12 @@ zebra_interface_nbr_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   ifindex = stream_getl (s);
 
   /* Lookup index. */
-  ifp = if_lookup_by_index (ifindex);
+  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
   if (ifp == NULL)
     {
-      zlog_warn ("zebra_nbr_interface_address_read(%s): "
-                 "Can't find interface by ifindex: %d ",
-                 (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD? "ADD" : "DELETE"),
-                 ifindex);
+      zlog_warn ("INTERFACE_NBR_%s: Cannot find IF %u in VRF %d",
+                 (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD) ? "ADD" : "DELETE",
+                 ifindex, vrf_id);
       return NULL;
     }
 
@@ -1116,6 +1281,33 @@ zebra_interface_nbr_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   return ifc;
 }
 
+struct interface *
+zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
+                                 vrf_id_t *new_vrf_id)
+{
+  unsigned int ifindex;
+  struct interface *ifp;
+  vrf_id_t new_id = VRF_DEFAULT;
+
+  /* Get interface index. */
+  ifindex = stream_getl (s);
+
+  /* Lookup interface. */
+  ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+  if (ifp == NULL)
+    {
+      zlog_warn ("INTERFACE_VRF_UPDATE: Cannot find IF %u in VRF %d",
+                 ifindex, vrf_id);
+      return NULL;
+    }
+
+  /* Fetch new VRF Id. */
+  new_id = stream_getw (s);
+
+  *new_vrf_id = new_id;
+  return ifp;
+}
+
 /* Zebra client message read function. */
 static int
 zclient_read (struct thread *thread)
@@ -1218,6 +1410,12 @@ zclient_read (struct thread *thread)
       if (zclient->router_id_update)
        (*zclient->router_id_update) (command, zclient, length, vrf_id);
       break;
+    case ZEBRA_VRF_ADD:
+      zclient_vrf_add (zclient, vrf_id);
+      break;
+    case ZEBRA_VRF_DELETE:
+      zclient_vrf_delete (zclient, vrf_id);
+      break;
     case ZEBRA_INTERFACE_ADD:
       if (zclient->interface_add)
        (*zclient->interface_add) (command, zclient, length, vrf_id);
@@ -1254,6 +1452,10 @@ zclient_read (struct thread *thread)
       if (zclient->interface_down)
        (*zclient->interface_down) (command, zclient, length, vrf_id);
       break;
+    case ZEBRA_INTERFACE_VRF_UPDATE:
+      if (zclient->interface_vrf_update)
+       (*zclient->interface_vrf_update) (command, zclient, length, vrf_id);
+      break;
     case ZEBRA_IPV4_ROUTE_ADD:
       if (zclient->ipv4_route_add)
        (*zclient->ipv4_route_add) (command, zclient, length, vrf_id);
@@ -1406,6 +1608,11 @@ zclient_event (enum event event, struct zclient *zclient)
     }
 }
 
+const char *zclient_serv_path_get()
+{
+  return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH;
+}
+
 void
 zclient_serv_path_set (char *path)
 {