isisd: allow to adjust lsp-mtu
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 6ecaca6..9fe11c2 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -578,6 +578,29 @@
}
}
+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 @@
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 @@
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 @@
}
/* 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 @@
struct isis_circuit *circuit;
struct interface *ifp;
struct isis_area *area;
+ int rv;
ifp = (struct interface *) vty->index;
assert (ifp);
@@ -1221,16 +1248,25 @@
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 @@
struct isis_circuit *circuit;
struct interface *ifp;
struct isis_area *area;
+ int rv;
ifp = (struct interface *) vty->index;
assert (ifp);
@@ -1319,16 +1356,25 @@
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,
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index d86fee0..d883879 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -164,5 +164,7 @@
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 */
diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h
index bb2c4b4..8b21894 100644
--- a/isisd/isis_constants.h
+++ b/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
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 050a9f9..dc18aa0 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -575,15 +575,16 @@
}
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_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 @@
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 @@
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->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 @@
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. */
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index 6e7f745..92a5dfe 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -66,7 +66,8 @@
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,
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 26efe4d..0c3f57f 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -1895,9 +1895,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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)
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 20b8e50..7146689 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -158,13 +158,11 @@
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 @@
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 @@
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 @@
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);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 838a08b..6e95e8e 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -91,7 +91,8 @@
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 */