Browse Source

isisd: allow to adjust lsp-mtu

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Christian Franke 3 years ago
parent
commit
f1fc1db703
8 changed files with 172 additions and 63 deletions
  1. 64 18
      isisd/isis_circuit.c
  2. 2 0
      isisd/isis_circuit.h
  3. 0 1
      isisd/isis_constants.h
  4. 12 12
      isisd/isis_lsp.c
  5. 2 1
      isisd/isis_lsp.h
  6. 9 27
      isisd/isis_pdu.c
  7. 81 3
      isisd/isisd.c
  8. 2 1
      isisd/isisd.h

+ 64 - 18
isisd/isis_circuit.c

@@ -578,6 +578,29 @@ isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set)
     }
 }
 
+size_t
+isis_circuit_pdu_size(struct isis_circuit *circuit)
+{
+  return ISO_MTU(circuit);
+}
+
+void
+isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
+{
+  size_t stream_size = isis_circuit_pdu_size(circuit);
+
+  if (!*stream)
+    {
+      *stream = stream_new(stream_size);
+    }
+  else
+    {
+      if (STREAM_SIZE(*stream) != stream_size)
+        stream_resize(*stream, stream_size);
+      stream_reset(*stream);
+    }
+}
+
 int
 isis_circuit_up (struct isis_circuit *circuit)
 {
@@ -592,6 +615,15 @@ isis_circuit_up (struct isis_circuit *circuit)
   if (circuit->is_passive)
     return ISIS_OK;
 
+  if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit))
+    {
+      zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!",
+               isis_circuit_pdu_size(circuit), circuit->interface->name,
+               circuit->area->lsp_mtu);
+      isis_circuit_down(circuit);
+      return ISIS_ERROR;
+    }
+
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {
       /*
@@ -624,9 +656,6 @@ isis_circuit_up (struct isis_circuit *circuit)
       circuit->u.bc.adjdb[0] = list_new ();
       circuit->u.bc.adjdb[1] = list_new ();
 
-      if (circuit->area->min_bcast_mtu == 0 ||
-          ISO_MTU (circuit) < circuit->area->min_bcast_mtu)
-        circuit->area->min_bcast_mtu = ISO_MTU (circuit);
       /*
        * ISO 10589 - 8.4.1 Enabling of broadcast circuits
        */
@@ -688,11 +717,8 @@ isis_circuit_up (struct isis_circuit *circuit)
     }
 
   /* initialize the circuit streams after opening connection */
-  if (circuit->rcv_stream == NULL)
-    circuit->rcv_stream = stream_new (ISO_MTU (circuit));
-
-  if (circuit->snd_stream == NULL)
-    circuit->snd_stream = stream_new (ISO_MTU (circuit));
+  isis_circuit_stream(circuit, &circuit->rcv_stream);
+  isis_circuit_stream(circuit, &circuit->snd_stream);
 
 #ifdef GNU_LINUX
   THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
@@ -1193,6 +1219,7 @@ DEFUN (ip_router_isis,
   struct isis_circuit *circuit;
   struct interface *ifp;
   struct isis_area *area;
+  int rv;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
@@ -1221,16 +1248,25 @@ DEFUN (ip_router_isis,
   area = vty->index;
 
   circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
-  isis_circuit_if_bind (circuit, ifp);
+  if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
+    {
+      vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE);
+      rv = CMD_WARNING;
+    }
+  else
+    {
+      isis_circuit_if_bind (circuit, ifp);
 
-  circuit->ip_router = 1;
-  area->ip_circuits++;
-  circuit_update_nlpids (circuit);
+      circuit->ip_router = 1;
+      area->ip_circuits++;
+      circuit_update_nlpids (circuit);
+      rv = CMD_SUCCESS;
+    }
 
   vty->node = INTERFACE_NODE;
   vty->index = ifp;
 
-  return CMD_SUCCESS;
+  return rv;
 }
 
 DEFUN (no_ip_router_isis,
@@ -1291,6 +1327,7 @@ DEFUN (ipv6_router_isis,
   struct isis_circuit *circuit;
   struct interface *ifp;
   struct isis_area *area;
+  int rv;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
@@ -1319,16 +1356,25 @@ DEFUN (ipv6_router_isis,
   area = vty->index;
 
   circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
-  isis_circuit_if_bind (circuit, ifp);
+  if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
+    {
+      vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE);
+      rv = CMD_WARNING;
+    }
+  else
+    {
+      isis_circuit_if_bind (circuit, ifp);
 
-  circuit->ipv6_router = 1;
-  area->ipv6_circuits++;
-  circuit_update_nlpids (circuit);
+      circuit->ipv6_router = 1;
+      area->ipv6_circuits++;
+      circuit_update_nlpids (circuit);
+      rv = CMD_SUCCESS;
+    }
 
   vty->node = INTERFACE_NODE;
   vty->index = ifp;
 
-  return CMD_SUCCESS;
+  return rv;
 }
 
 DEFUN (no_ipv6_router_isis,

+ 2 - 0
isisd/isis_circuit.h

@@ -164,5 +164,7 @@ void isis_circuit_down (struct isis_circuit *);
 void circuit_update_nlpids (struct isis_circuit *circuit);
 void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
                              char detail);
+size_t isis_circuit_pdu_size(struct isis_circuit *circuit);
+void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream);
 
 #endif /* _ZEBRA_ISIS_CIRCUIT_H */

+ 0 - 1
isisd/isis_constants.h

@@ -34,7 +34,6 @@
 #define ISO_SAP                       0xFE
 #define INTRADOMAIN_ROUTEING_SELECTOR 0
 #define SEQUENCE_MODULUS              4294967296
-#define RECEIVE_LSP_BUFFER_SIZE       1492
 
 /*
  * implementation specific jitter values

+ 12 - 12
isisd/isis_lsp.c

@@ -575,15 +575,16 @@ lsp_new_from_stream_ptr (struct stream *stream,
 }
 
 struct isis_lsp *
-lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
-	 u_int8_t lsp_bits, u_int16_t checksum, int level)
+lsp_new(struct isis_area *area, u_char * lsp_id,
+	u_int16_t rem_lifetime, u_int32_t seq_num,
+	u_int8_t lsp_bits, u_int16_t checksum, int level)
 {
   struct isis_lsp *lsp;
 
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
+  lsp->area = area;
 
-  /* FIXME: Should be minimal mtu? */
-  lsp->pdu = stream_new (1500);
+  lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
   if (LSP_FRAGMENT (lsp_id) == 0)
     lsp->lspu.frags = list_new ();
   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
@@ -1131,7 +1132,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
       lsp_clear_data (lsp);
       return lsp;
     }
-  lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
+  lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
                  lsp_bits_generate (level, area->overload_bit,
                  area->attached_bit), 0, level);
   lsp->area = area;
@@ -1593,7 +1594,7 @@ lsp_generate (struct isis_area *area, int level)
                               area->lspdb[level - 1]);
     }
   rem_lifetime = lsp_rem_lifetime (area, level);
-  newlsp = lsp_new (lspid, rem_lifetime, seq_num,
+  newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
                     area->is_type | area->overload_bit | area->attached_bit,
                     0, level);
   newlsp->area = area;
@@ -1966,7 +1967,7 @@ lsp_generate_pseudo (struct isis_circuit *circuit, int level)
 
   rem_lifetime = lsp_rem_lifetime (circuit->area, level);
   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-  lsp = lsp_new (lsp_id, rem_lifetime, 1,
+  lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
                  circuit->area->is_type | circuit->area->attached_bit,
                  0, level);
   lsp->area = circuit->area;
@@ -2356,8 +2357,7 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
   lsp->area = area;
   lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ?
     IS_LEVEL_1 : IS_LEVEL_2;
-  /* FIXME: Should be minimal mtu? */
-  lsp->pdu = stream_new (1500);
+  lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
   lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
   fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
 		  : L2_LINK_STATE);
@@ -2479,11 +2479,11 @@ generate_topology_lsps (struct isis_area *area)
       lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
 
       rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
-      lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit
-                     | area->attached_bit, 0, 1);
+      lsp = lsp_new (area, lspid, rem_lifetime, 1,
+                     IS_LEVEL_1 | area->overload_bit | area->attached_bit,
+                     0, 1);
       if (!lsp)
 	return;
-      lsp->area = area;
       lsp->from_topology = 1;
 
       /* Creating LSP data based on topology info. */

+ 2 - 1
isisd/isis_lsp.h

@@ -66,7 +66,8 @@ int lsp_regenerate_schedule (struct isis_area *area, int level,
 int lsp_generate_pseudo (struct isis_circuit *circuit, int level);
 int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level);
 
-struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime,
+struct isis_lsp *lsp_new (struct isis_area *area, u_char * lsp_id,
+			  u_int16_t rem_lifetime,
 			  u_int32_t seq_num, u_int8_t lsp_bits,
 			  u_int16_t checksum, int level);
 struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream,

+ 9 - 27
isisd/isis_pdu.c

@@ -1895,9 +1895,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
 	    if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
 		memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
 	      {
-		lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
-			       0, 0, entry->checksum, level);
-		lsp->area = circuit->area;
+		lsp = lsp_new(circuit->area, entry->lsp_id,
+			      ntohs(entry->rem_lifetime),
+			      0, 0, entry->checksum, level);
 		lsp_insert (lsp, circuit->area->lspdb[level - 1]);
 		ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
 		ISIS_SET_FLAG (lsp->SSNflags, circuit);
@@ -2121,10 +2121,7 @@ isis_receive (struct thread *thread)
   circuit = THREAD_ARG (thread);
   assert (circuit);
 
-  if (circuit->rcv_stream == NULL)
-    circuit->rcv_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->rcv_stream);
+  isis_circuit_stream(circuit, &circuit->rcv_stream);
 
   retval = circuit->rx (circuit, ssnpa);
   circuit->t_read = NULL;
@@ -2160,10 +2157,7 @@ isis_receive (struct thread *thread)
 
   circuit->t_read = NULL;
 
-  if (circuit->rcv_stream == NULL)
-    circuit->rcv_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->rcv_stream);
+  isis_circuit_stream(circuit, &circuit->rcv_stream);
 
   retval = circuit->rx (circuit, ssnpa);
 
@@ -2268,10 +2262,7 @@ send_hello (struct isis_circuit *circuit, int level)
       return ISIS_WARNING;
     }
 
-  if (!circuit->snd_stream)
-    circuit->snd_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->snd_stream);
+  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     if (level == IS_LEVEL_1)
@@ -2527,10 +2518,7 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
   unsigned long auth_tlv_offset = 0;
   int retval = ISIS_OK;
 
-  if (circuit->snd_stream == NULL)
-    circuit->snd_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->snd_stream);
+  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
@@ -2854,10 +2842,7 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
   unsigned long auth_tlv_offset = 0;
   int retval = ISIS_OK;
 
-  if (circuit->snd_stream == NULL)
-    circuit->snd_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->snd_stream);
+  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
@@ -3179,10 +3164,7 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
   u_int16_t length;
   struct isis_fixed_hdr fixed_hdr;
 
-  if (!circuit->snd_stream)
-    circuit->snd_stream = stream_new (ISO_MTU (circuit));
-  else
-    stream_reset (circuit->snd_stream);
+  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   //  fill_llc_hdr (stream);
   if (level == IS_LEVEL_1)

+ 81 - 3
isisd/isisd.c

@@ -158,13 +158,11 @@ isis_area_create (const char *area_tag)
   area->oldmetric = 0;
   area->newmetric = 1;
   area->lsp_frag_threshold = 90;
+  area->lsp_mtu = DEFAULT_LSP_MTU;
 #ifdef TOPOLOGY_GENERATE
   memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
 #endif /* TOPOLOGY_GENERATE */
 
-  /* FIXME: Think of a better way... */
-  area->min_bcast_mtu = 1497;
-
   area->area_tag = strdup (area_tag);
   listnode_add (isis->area_list, area);
   area->isis = isis;
@@ -1545,6 +1543,76 @@ DEFUN (no_net,
   return area_clear_net_title (vty, argv[0]);
 }
 
+static
+int area_set_lsp_mtu(struct vty *vty, struct isis_area *area, unsigned int lsp_mtu)
+{
+  struct isis_circuit *circuit;
+  struct listnode *node;
+
+  for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+    {
+      if(lsp_mtu > isis_circuit_pdu_size(circuit))
+        {
+          vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s",
+                  circuit->interface->name, isis_circuit_pdu_size(circuit),
+                  VTY_NEWLINE);
+          return CMD_ERR_AMBIGUOUS;
+        }
+    }
+
+  area->lsp_mtu = lsp_mtu;
+  lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (area_lsp_mtu,
+       area_lsp_mtu_cmd,
+       "lsp-mtu <128-4352>",
+       "Configure the maximum size of generated LSPs\n"
+       "Maximum size of generated LSPs\n")
+{
+  struct isis_area *area;
+
+  area = vty->index;
+  if (!area)
+    {
+      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  unsigned int lsp_mtu;
+
+  VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352);
+
+  return area_set_lsp_mtu(vty, area, lsp_mtu);
+}
+
+DEFUN(no_area_lsp_mtu,
+      no_area_lsp_mtu_cmd,
+      "no lsp-mtu",
+      NO_STR
+      "Configure the maximum size of generated LSPs\n")
+{
+  struct isis_area *area;
+
+  area = vty->index;
+  if (!area)
+    {
+      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+    }
+
+  return area_set_lsp_mtu(vty, area, DEFAULT_LSP_MTU);
+}
+
+ALIAS(no_area_lsp_mtu,
+      no_area_lsp_mtu_arg_cmd,
+      "no lsp-mtu <128-4352>",
+      NO_STR
+      "Configure the maximum size of generated LSPs\n"
+      "Maximum size of generated LSPs\n");
+
 DEFUN (area_passwd_md5,
        area_passwd_md5_cmd,
        "area-password md5 WORD",
@@ -2990,6 +3058,12 @@ isis_config_write (struct vty *vty)
 		write++;
 	      }
 	  }
+	if (area->lsp_mtu != DEFAULT_LSP_MTU)
+	  {
+	    vty_out(vty, " lsp-mtu %u%s", area->lsp_mtu, VTY_NEWLINE);
+	    write++;
+	  }
+
 	/* Minimum SPF interval. */
 	if (area->min_spf_interval[0] == area->min_spf_interval[1])
 	  {
@@ -3223,6 +3297,10 @@ isis_init ()
   install_element (ISIS_NODE, &is_type_cmd);
   install_element (ISIS_NODE, &no_is_type_cmd);
 
+  install_element (ISIS_NODE, &area_lsp_mtu_cmd);
+  install_element (ISIS_NODE, &no_area_lsp_mtu_cmd);
+  install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd);
+
   install_element (ISIS_NODE, &area_passwd_md5_cmd);
   install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd);
   install_element (ISIS_NODE, &area_passwd_clear_cmd);

+ 2 - 1
isisd/isisd.h

@@ -91,7 +91,8 @@ struct isis_area
   struct isis_spftree *spftree6[ISIS_LEVELS];	  /* The v6 SPTs */
   struct route_table *route_table6[ISIS_LEVELS];  /* IPv6 routes */
 #endif
-  unsigned int min_bcast_mtu;
+#define DEFAULT_LSP_MTU 1497
+  unsigned int lsp_mtu;				  /* Size of LSPs to generate */
   struct list *circuit_list;	/* IS-IS circuits */
   struct flags flags;
   struct thread *t_tick;	/* LSP walker */