]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: fec register
authorDon Slice <dslice@cumulusnetworks.com>
Wed, 1 Feb 2017 18:10:56 +0000 (13:10 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 14:29:19 +0000 (10:29 -0400)
Implement interface that allows a client to register a FEC for obtaining
a label binding (in-label). Update client whenever the label binding is
updated and cleanup when client goes away.

Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
lib/zclient.c
lib/zclient.h
zebra/Makefile.am
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_null.c
zebra/zserv.c

index 71b95ae7dbadcc8e3e4cad14b7c28ae33eb5d264..9e53b66c77cb509c96f8ccb11d026a5d25a68af1 100644 (file)
@@ -1867,6 +1867,12 @@ zclient_read (struct thread *thread)
       if (zclient->interface_link_params)
         (*zclient->interface_link_params) (command, zclient, length);
       break;
+    case ZEBRA_FEC_UPDATE:
+      if (zclient_debug)
+        zlog_debug("zclient rcvd fec update\n");
+      if (zclient->fec_update)
+        (*zclient->fec_update) (command, zclient, length);
+      break;
     default:
       break;
     }
index d3d0a202c5caf379bcaf3d56324fb9bd6db33b87..a5a1b530c5e5df9e7659c3d03a4fa6e39a6c6eb6 100644 (file)
@@ -94,6 +94,9 @@ typedef enum {
   ZEBRA_LABEL_MANAGER_CONNECT,
   ZEBRA_GET_LABEL_CHUNK,
   ZEBRA_RELEASE_LABEL_CHUNK,
+  ZEBRA_FEC_REGISTER,
+  ZEBRA_FEC_UNREGISTER,
+  ZEBRA_FEC_UPDATE,
 } zebra_message_types_t;
 
 struct redist_proto
@@ -164,6 +167,7 @@ struct zclient
   int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
+  int (*fec_update) (int, struct zclient *, uint16_t);
 };
 
 /* Zebra API message flag. */
index 3e0de3b4631c7b913b111f7f46760e0d999a7ffa..821264a15e3a45a1ce469734f1bb57cdc0270815 100644 (file)
@@ -40,7 +40,7 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
        zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
        kernel_null.c  redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
        zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
-       zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c
+       zebra_memory.c zebra_mpls_vty.c zebra_mpls_null.c
 
 noinst_HEADERS = \
        zebra_memory.h \
index 814d171d9f50deab34f9aa95c7c428ab5850df37..366853cc006a094487722d95ce235674aced1b1a 100644 (file)
@@ -60,6 +60,10 @@ extern struct zebra_t zebrad;
 
 /* static function declarations */
 
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client);
+static void
+fec_update_clients (zebra_fec_t *fec);
 static void
 fec_print (zebra_fec_t *fec, struct vty *vty);
 static zebra_fec_t *
@@ -148,6 +152,49 @@ mpls_processq_init (struct zebra_t *zebra);
 
 /* Static functions */
 
+/*
+ * Inform about FEC to a registered client.
+ */
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client)
+{
+  struct stream *s;
+  struct route_node *rn;
+
+  rn = fec->rn;
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
+
+  stream_putw(s, rn->p.family);
+  stream_put_prefix (s, &rn->p);
+  stream_putl(s, fec->label);
+  stream_putw_at(s, 0, stream_get_endp(s));
+  return zebra_server_send_message(client);
+}
+
+/*
+ * Update all registered clients about this FEC. Caller should've updated
+ * FEC and ensure no duplicate updates.
+ */
+static void
+fec_update_clients (zebra_fec_t *fec)
+{
+  struct listnode *node;
+  struct zserv *client;
+
+  for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update client %s", zebra_route_string(client->proto));
+      fec_send(fec, client);
+    }
+}
+
+
 /*
  * Print a FEC-label binding entry.
  */
@@ -155,6 +202,8 @@ static void
 fec_print (zebra_fec_t *fec, struct vty *vty)
 {
   struct route_node *rn;
+  struct listnode *node;
+  struct zserv *client;
   char buf[BUFSIZ];
 
   rn = fec->rn;
@@ -162,6 +211,14 @@ fec_print (zebra_fec_t *fec, struct vty *vty)
   vty_out(vty, "%s%s", buf, VTY_NEWLINE);
   vty_out(vty, "  Label: %s", label2str(fec->label, buf, BUFSIZ));
   vty_out(vty, "%s", VTY_NEWLINE);
+  if (!list_isempty(fec->client_list))
+    {
+      vty_out(vty, "  Client list:");
+      for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+        vty_out(vty, " %s(fd %d)",
+                zebra_route_string(client->proto), client->sock);
+      vty_out(vty, "%s", VTY_NEWLINE);
+    }
 }
 
 /*
@@ -182,7 +239,8 @@ fec_find (struct route_table *table, struct prefix *p)
 }
 
 /*
- * Add a FEC.
+ * Add a FEC. This may be upon a client registering for a binding
+ * or when a binding is configured.
  */
 static zebra_fec_t *
 fec_add (struct route_table *table, struct prefix *p,
@@ -209,6 +267,7 @@ fec_add (struct route_table *table, struct prefix *p,
       rn->info = fec;
       fec->rn = rn;
       fec->label = label;
+      fec->client_list = list_new();
     }
   else
     route_unlock_node (rn); /* for the route_node_get */
@@ -219,11 +278,14 @@ fec_add (struct route_table *table, struct prefix *p,
 }
 
 /*
- * Delete a FEC.
+ * Delete a FEC. This may be upon the last client deregistering for
+ * a FEC and no binding exists or when the binding is deleted and there
+ * are no registered clients.
  */
 static int
 fec_del (zebra_fec_t *fec)
 {
+  list_free (fec->client_list);
   fec->rn->info = NULL;
   route_unlock_node (fec->rn);
   XFREE (MTYPE_FEC, fec);
@@ -1370,6 +1432,142 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
   return buf;
 }
 
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         struct zserv *client)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  /* Locate FEC */
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      fec = fec_add (table, p, MPLS_INVALID_LABEL, 0);
+      if (!fec)
+        {
+          prefix2str(p, buf, BUFSIZ);
+          zlog_err("Failed to add FEC %s upon register, client %s",
+                   buf, zebra_route_string(client->proto));
+          return -1;
+        }
+    }
+  else
+    {
+      if (listnode_lookup(fec->client_list, client))
+        /* Duplicate register */
+        return 0;
+    }
+
+  listnode_add (fec->client_list, client);
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    zlog_debug("FEC %s registered by client %s",
+                buf, zebra_route_string(client->proto));
+
+  if (fec->label != MPLS_INVALID_LABEL)
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update client label %u", fec->label);
+      fec_send (fec, client);
+    }
+
+  return 0;
+}
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      prefix2str(p, buf, BUFSIZ);
+      zlog_err("Failed to find FEC %s upon unregister, client %s",
+               buf, zebra_route_string(client->proto));
+      return -1;
+    }
+
+  listnode_delete(fec->client_list, client);
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    zlog_debug("FEC %s unregistered by client %s",
+                buf, zebra_route_string(client->proto));
+
+  if (list_isempty(fec->client_list) && (fec->label == MPLS_INVALID_LABEL))
+    fec_del (fec);
+
+  return 0;
+}
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+  struct route_node *rn;
+  zebra_fec_t *fec;
+  struct listnode *node;
+  struct zserv *fec_client;
+  int af;
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      if (zvrf->fec_table[af] == NULL)
+        continue;
+
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          fec = rn->info;
+          if (!fec || list_isempty(fec->client_list))
+            continue;
+
+          for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client))
+            {
+              if (fec_client == client)
+                {
+                  listnode_delete(fec->client_list, fec_client);
+                  if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+                      list_isempty(fec->client_list))
+                    fec_del (fec);
+                  break;
+                }
+            }
+        }
+    }
+
+  return 0;
+}
+
 /*
  * Return FEC (if any) to which this label is bound.
  * Note: Only works for per-prefix binding and when the label is not
@@ -1412,8 +1610,9 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
 }
 
 /*
- * Add static FEC to label binding.
- */
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them.
+*/
 int
 zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
                            mpls_label_t in_label)
@@ -1452,17 +1651,20 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
         /* Duplicate config */
         return 0;
 
+      /* Label change, update clients. */
       if (IS_ZEBRA_DEBUG_MPLS)
         zlog_debug ("Update fec %s new label %u", buf, in_label);
 
       fec->label = in_label;
+      fec_update_clients (fec);
     }
 
   return ret;
 }
 
 /*
- * Remove static FEC to label binding.
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients
  */
 int
 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
@@ -1489,7 +1691,18 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
       zlog_debug ("Delete fec %s", buf);
     }
 
-  fec_del (fec);
+  fec->flags &= ~FEC_FLAG_CONFIGURED;
+  fec->label = MPLS_INVALID_LABEL;
+
+  /* If no client exists, just delete the FEC. */
+  if (list_isempty(fec->client_list))
+    {
+      fec_del (fec);
+      return 0;
+    }
+
+  fec_update_clients (fec);
+
   return 0;
 }
 
index 9ff230e5eee41b42eb231ff9225cd84808c8f57d..4636a28c10c2c6965aa10ba125ec52576a7defc9 100644 (file)
@@ -162,6 +162,9 @@ struct zebra_fec_t_
   /* Flags. */
   u_int32_t flags;
 #define FEC_FLAG_CONFIGURED       (1 << 0)
+
+  /* Clients interested in this FEC. */
+  struct list *client_list;
 };
 
 /* Function declarations. */
@@ -180,6 +183,29 @@ char *
 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
                 char *buf, int len);
 
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         struct zserv *client);
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client);
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
+
 /*
  * Return FEC (if any) to which this label is bound.
  * Note: Only works for per-prefix binding and when the label is not
@@ -197,14 +223,16 @@ int
 zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
 
 /*
- * Add static FEC to label binding.
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them.
  */
 int
 zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
                            mpls_label_t in_label);
 
 /*
- * Remove static FEC to label binding.
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients.
  */
 int
 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
index 23f5e72956415a345ef48aa2a6810ffb7fe38162..29990928d3d0bbae7551f8c35e55d338fd4ee9cc 100644 (file)
@@ -27,3 +27,138 @@ int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
 int mpls_kernel_init (void) { return -1; };
+
+int mpls_enabled;
+
+char *
+mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
+                char *buf, int len)
+{
+  return NULL;
+}
+
+int
+mpls_str2label (const char *label_str, u_int8_t *num_labels,
+                mpls_label_t *labels)
+{
+  return 0;
+}
+
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
+                      u_char use_json)
+{
+}
+
+void
+zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
+                            u_char use_json)
+{
+}
+
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+int
+zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                                 mpls_label_t out_label, enum nexthop_types_t gtype,
+                                 union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                           mpls_label_t out_label, enum nexthop_types_t gtype,
+                           union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                           enum nexthop_types_t gtype, union g_addr *gate,
+                           char *ifname, ifindex_t ifindex)
+{
+  return 0;
+}
+
+void
+zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_close_tables (struct zebra_vrf *zvrf)
+{
+}
+
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  return NULL;
+}
+
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+  return 0;
+}
+
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+}
+
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         struct zserv *client)
+{
+  return 0;
+}
+
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client)
+{
+  return 0;
+}
+
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+  return 0;
+}
+
index 3477dc36d2ccb355295d1a099fa559e9e9502281..73ea58980565ebfe03d65d4885052e113ed760fb 100644 (file)
@@ -934,6 +934,60 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
   return 0;
 }
 
+/* FEC register */
+static int
+zserv_fec_register (struct zserv *client, int sock, u_short length)
+{
+  struct stream *s;
+  struct zebra_vrf *zvrf;
+  u_short l = 0;
+  struct prefix p;
+
+  s = client->ibuf;
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    return 0; // unexpected
+
+  while (l < length)
+    {
+      p.family = stream_getw(s);
+      p.prefixlen = stream_getc(s);
+      l += 5;
+      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+      l += PSIZE(p.prefixlen);
+      zebra_mpls_fec_register (zvrf, &p, client);
+    }
+
+  return 0;
+}
+
+/* FEC unregister */
+static int
+zserv_fec_unregister (struct zserv *client, int sock, u_short length)
+{
+  struct stream *s;
+  struct zebra_vrf *zvrf;
+  u_short l = 0;
+  struct prefix p;
+
+  s = client->ibuf;
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    return 0;  // unexpected
+
+  while (l < length)
+    {
+      p.family = stream_getw(s);
+      p.prefixlen = stream_getc(s);
+      l += 5;
+      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+      l += PSIZE(p.prefixlen);
+      zebra_mpls_fec_unregister (zvrf, &p, client);
+    }
+
+  return 0;
+}
+
 /*
   Modified version of zsend_ipv4_nexthop_lookup():
   Query unicast rib if nexthop is not found on mrib.
@@ -1975,6 +2029,9 @@ zebra_client_close (struct zserv *client)
   /* Release Label Manager chunks */
   release_daemon_chunks (client->proto, client->instance);
 
+ /* Cleanup any FECs registered by this client. */
+  zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
+
   /* Close file descriptor. */
   if (client->sock)
     {
@@ -2263,6 +2320,12 @@ zebra_client_read (struct thread *thread)
     case ZEBRA_RELEASE_LABEL_CHUNK:
       zread_label_manager_request (command, client, vrf_id);
       break;
+    case ZEBRA_FEC_REGISTER:
+      zserv_fec_register (client, sock, length);
+      break;
+    case ZEBRA_FEC_UNREGISTER:
+      zserv_fec_unregister (client, sock, length);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;