From 9570f7378bb9e000fc4e98fa2f0ef6356af4a548 Mon Sep 17 00:00:00 2001 From: Saravanan K Date: Mon, 25 Mar 2019 06:23:17 -0700 Subject: [PATCH] ospfd: Remaining packet calculation while fragmenting lsu, ls-ack and ls-req While fragmenting ospf ls packets, before appending the link state info, wrong value is checked to see if current packet can fit in another ls info. Because of this, when a lower mtu is configured, it couldn't fit in even 1 ls ack, which tries to send all the available ls ack in the list in loop. This keeps allocating memory to send the packet and ends up putting the packet buffer without ls-ack into deferred send que(ospf_ls_ack_send_delayed). This infinite loop causes infinite memory being allocated in a loop causing system to be unstable. This commit takes care of calculating the right value to compare for checking oif this buffer can fit in more. Signed-off-by: Saravanan K --- ospfd/ospf_packet.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b3c91b9006..43c5e338b0 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length, oi = nbr->oi; - /* LS Request packet overflows interface MTU. */ + /* LS Request packet overflows interface MTU + * delta is just number of bytes required for 1 LS Req + * ospf_packet_max will return the number of bytes can + * be accomodated without ospf header. So length+delta + * can be compared to ospf_packet_max + * to check if it can fit another lsreq in the same packet. + */ + if (*length + delta > ospf_packet_max(oi)) return 0; @@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s) { struct ospf_lsa *lsa; uint16_t length = OSPF_LS_REQ_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 12; + unsigned long delta = 12; struct route_table *table; struct route_node *rn; int i; @@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, assert(lsa->data); - /* Will it fit? */ - if (length + delta + ntohs(lsa->data->length) > size_noauth) + /* Will it fit? Minimum it has to fit atleast one */ + if ((length + delta + ntohs(lsa->data->length) > size_noauth) && + (count > 0)) break; /* Keep pointer to LS age. */ @@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, { struct listnode *node, *nnode; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 24; + unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { assert(lsa); - if (length + delta > ospf_packet_max(oi)) + /* LS Ack packet overflows interface MTU + * delta is just number of bytes required for + * 1 LS Ack(1 LS Hdr) ospf_packet_max will return + * the number of bytes can be accomodated without + * ospf header. So length+delta can be compared + * against ospf_packet_max to check if it can fit + * another ls header in the same packet. + */ + if ((length + delta) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); -- 2.39.5