back to topotato report
topotato coverage report
Current view: top level - pimd - pim_msdp_packet.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 0 389 0.0 %
Date: 2023-02-24 14:41:08 Functions: 0 26 0.0 %

          Line data    Source code
       1             : /*
       2             :  * IP MSDP packet helper
       3             :  * Copyright (C) 2016 Cumulus Networks, Inc.
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation; either version 2 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : #include <zebra.h>
      20             : 
      21             : #include <lib/log.h>
      22             : #include <lib/network.h>
      23             : #include <lib/stream.h>
      24             : #include <lib/thread.h>
      25             : #include <lib/vty.h>
      26             : #include <lib/lib_errors.h>
      27             : 
      28             : #include "pimd.h"
      29             : #include "pim_instance.h"
      30             : #include "pim_str.h"
      31             : #include "pim_errors.h"
      32             : 
      33             : #include "pim_msdp.h"
      34             : #include "pim_msdp_packet.h"
      35             : #include "pim_msdp_socket.h"
      36             : 
      37           0 : static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
      38             :                                     int buf_size)
      39             : {
      40           0 :         switch (type) {
      41           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE:
      42           0 :                 snprintf(buf, buf_size, "%s", "SA");
      43           0 :                 break;
      44           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
      45           0 :                 snprintf(buf, buf_size, "%s", "SA_REQ");
      46           0 :                 break;
      47           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
      48           0 :                 snprintf(buf, buf_size, "%s", "SA_RESP");
      49           0 :                 break;
      50           0 :         case PIM_MSDP_KEEPALIVE:
      51           0 :                 snprintf(buf, buf_size, "%s", "KA");
      52           0 :                 break;
      53           0 :         case PIM_MSDP_RESERVED:
      54           0 :                 snprintf(buf, buf_size, "%s", "RSVD");
      55           0 :                 break;
      56           0 :         case PIM_MSDP_TRACEROUTE_PROGRESS:
      57           0 :                 snprintf(buf, buf_size, "%s", "TRACE_PROG");
      58           0 :                 break;
      59           0 :         case PIM_MSDP_TRACEROUTE_REPLY:
      60           0 :                 snprintf(buf, buf_size, "%s", "TRACE_REPLY");
      61           0 :                 break;
      62           0 :         default:
      63           0 :                 snprintf(buf, buf_size, "UNK-%d", type);
      64             :         }
      65           0 :         return buf;
      66             : }
      67             : 
      68           0 : static void pim_msdp_pkt_sa_dump_one(struct stream *s)
      69             : {
      70           0 :         pim_sgaddr sg;
      71             : 
      72             :         /* just throw away the three reserved bytes */
      73           0 :         stream_get3(s);
      74             :         /* throw away the prefix length also */
      75           0 :         stream_getc(s);
      76             : 
      77           0 :         memset(&sg, 0, sizeof(sg));
      78           0 :         sg.grp.s_addr = stream_get_ipv4(s);
      79           0 :         sg.src.s_addr = stream_get_ipv4(s);
      80             : 
      81           0 :         zlog_debug("  sg %pSG", &sg);
      82           0 : }
      83             : 
      84           0 : static void pim_msdp_pkt_sa_dump(struct stream *s)
      85             : {
      86           0 :         const size_t header_length = PIM_MSDP_SA_X_SIZE - PIM_MSDP_HEADER_SIZE;
      87           0 :         size_t payload_length;
      88           0 :         int entry_cnt;
      89           0 :         int i;
      90           0 :         struct in_addr rp; /* Last RP address associated with this SA */
      91             : 
      92           0 :         if (header_length > STREAM_READABLE(s)) {
      93           0 :                 zlog_err("BUG MSDP SA bad header (readable %zu expected %zu)",
      94             :                          STREAM_READABLE(s), header_length);
      95           0 :                 return;
      96             :         }
      97             : 
      98           0 :         entry_cnt = stream_getc(s);
      99           0 :         rp.s_addr = stream_get_ipv4(s);
     100             : 
     101           0 :         if (PIM_DEBUG_MSDP_PACKETS) {
     102           0 :                 char rp_str[INET_ADDRSTRLEN];
     103           0 :                 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
     104           0 :                 zlog_debug("  entry_cnt %d rp %s", entry_cnt, rp_str);
     105             :         }
     106             : 
     107           0 :         payload_length = (size_t)entry_cnt * PIM_MSDP_SA_ONE_ENTRY_SIZE;
     108           0 :         if (payload_length > STREAM_READABLE(s)) {
     109           0 :                 zlog_err("BUG MSDP SA bad length (readable %zu expected %zu)",
     110             :                          STREAM_READABLE(s), payload_length);
     111           0 :                 return;
     112             :         }
     113             : 
     114             :         /* dump SAs */
     115           0 :         for (i = 0; i < entry_cnt; ++i) {
     116           0 :                 pim_msdp_pkt_sa_dump_one(s);
     117             :         }
     118             : }
     119             : 
     120           0 : static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
     121             :                               bool rx, struct stream *s)
     122             : {
     123           0 :         char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
     124             : 
     125           0 :         pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
     126             : 
     127           0 :         zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
     128             :                    rx ? "rx" : "tx", type_str, len);
     129             : 
     130           0 :         if (!s) {
     131           0 :                 return;
     132             :         }
     133             : 
     134           0 :         if (len < PIM_MSDP_HEADER_SIZE) {
     135           0 :                 zlog_err("invalid MSDP header length");
     136           0 :                 return;
     137             :         }
     138             : 
     139           0 :         switch (type) {
     140           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE:
     141           0 :                 pim_msdp_pkt_sa_dump(s);
     142           0 :                 break;
     143           0 :         default:;
     144             :         }
     145             : }
     146             : 
     147             : /* Check file descriptor whether connect is established. */
     148           0 : static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
     149             : {
     150           0 :         int status;
     151           0 :         socklen_t slen;
     152           0 :         int ret;
     153             : 
     154           0 :         if (mp->state != PIM_MSDP_CONNECTING) {
     155             :                 /* if we are here it means we are not in a connecting or
     156             :                  * established state
     157             :                  * for now treat this as a fatal error */
     158           0 :                 pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
     159           0 :                 return;
     160             :         }
     161             : 
     162           0 :         PIM_MSDP_PEER_READ_OFF(mp);
     163           0 :         PIM_MSDP_PEER_WRITE_OFF(mp);
     164             : 
     165             :         /* Check file descriptor. */
     166           0 :         slen = sizeof(status);
     167           0 :         ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
     168             : 
     169             :         /* If getsockopt is fail, this is fatal error. */
     170           0 :         if (ret < 0) {
     171           0 :                 flog_err_sys(EC_LIB_SOCKET,
     172             :                              "can't get sockopt for nonblocking connect");
     173           0 :                 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
     174           0 :                 return;
     175             :         }
     176             : 
     177             :         /* When status is 0 then TCP connection is established. */
     178           0 :         if (PIM_DEBUG_MSDP_INTERNAL) {
     179           0 :                 zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str,
     180             :                            status ? "fail" : "success");
     181             :         }
     182           0 :         if (status == 0) {
     183           0 :                 pim_msdp_peer_established(mp);
     184             :         } else {
     185           0 :                 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
     186             :         }
     187             : }
     188             : 
     189           0 : static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
     190             : {
     191           0 :         stream_free(stream_fifo_pop(mp->obuf));
     192           0 : }
     193             : 
     194           0 : static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
     195             : {
     196           0 :         stream_fifo_push(mp->obuf, s);
     197             : }
     198             : 
     199           0 : static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
     200             : {
     201           0 :         if (stream_fifo_head(mp->obuf)) {
     202           0 :                 PIM_MSDP_PEER_WRITE_ON(mp);
     203             :         }
     204           0 : }
     205             : 
     206           0 : void pim_msdp_write(struct thread *thread)
     207             : {
     208           0 :         struct pim_msdp_peer *mp;
     209           0 :         struct stream *s;
     210           0 :         int num;
     211           0 :         enum pim_msdp_tlv type;
     212           0 :         int len;
     213           0 :         int work_cnt = 0;
     214           0 :         int work_max_cnt = 100;
     215             : 
     216           0 :         mp = THREAD_ARG(thread);
     217           0 :         mp->t_write = NULL;
     218             : 
     219           0 :         if (PIM_DEBUG_MSDP_INTERNAL) {
     220           0 :                 zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
     221             :         }
     222           0 :         if (mp->fd < 0) {
     223             :                 return;
     224             :         }
     225             : 
     226             :         /* check if TCP connection is established */
     227           0 :         if (mp->state != PIM_MSDP_ESTABLISHED) {
     228           0 :                 pim_msdp_connect_check(mp);
     229           0 :                 return;
     230             :         }
     231             : 
     232           0 :         s = stream_fifo_head(mp->obuf);
     233           0 :         if (!s) {
     234           0 :                 pim_msdp_write_proceed_actions(mp);
     235           0 :                 return;
     236             :         }
     237             : 
     238             :         /* Nonblocking write until TCP output buffer is full  */
     239           0 :         do {
     240           0 :                 int writenum;
     241             : 
     242             :                 /* Number of bytes to be sent */
     243           0 :                 writenum = stream_get_endp(s) - stream_get_getp(s);
     244             : 
     245             :                 /* Call write() system call */
     246           0 :                 num = write(mp->fd, stream_pnt(s), writenum);
     247           0 :                 if (num < 0) {
     248             :                         /* write failed either retry needed or error */
     249           0 :                         if (ERRNO_IO_RETRY(errno)) {
     250           0 :                                 if (PIM_DEBUG_MSDP_INTERNAL) {
     251           0 :                                         zlog_debug(
     252             :                                                 "MSDP peer %s pim_msdp_write io retry",
     253             :                                                 mp->key_str);
     254             :                                 }
     255             :                                 break;
     256             :                         }
     257             : 
     258           0 :                         pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
     259           0 :                         return;
     260             :                 }
     261             : 
     262           0 :                 if (num != writenum) {
     263             :                         /* Partial write */
     264           0 :                         stream_forward_getp(s, num);
     265           0 :                         if (PIM_DEBUG_MSDP_INTERNAL) {
     266           0 :                                 zlog_debug(
     267             :                                         "MSDP peer %s pim_msdp_partial_write",
     268             :                                         mp->key_str);
     269             :                         }
     270             :                         break;
     271             :                 }
     272             : 
     273             :                 /* Retrieve msdp packet type. */
     274           0 :                 stream_set_getp(s, 0);
     275           0 :                 type = stream_getc(s);
     276           0 :                 len = stream_getw(s);
     277           0 :                 switch (type) {
     278           0 :                 case PIM_MSDP_KEEPALIVE:
     279           0 :                         mp->ka_tx_cnt++;
     280           0 :                         break;
     281           0 :                 case PIM_MSDP_V4_SOURCE_ACTIVE:
     282           0 :                         mp->sa_tx_cnt++;
     283           0 :                         break;
     284             :                 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
     285             :                 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
     286             :                 case PIM_MSDP_RESERVED:
     287             :                 case PIM_MSDP_TRACEROUTE_PROGRESS:
     288             :                 case PIM_MSDP_TRACEROUTE_REPLY:
     289             :                         break;
     290             :                 }
     291           0 :                 if (PIM_DEBUG_MSDP_PACKETS) {
     292           0 :                         pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
     293             :                 }
     294             : 
     295             :                 /* packet sent delete it. */
     296           0 :                 pim_msdp_pkt_delete(mp);
     297             : 
     298           0 :                 ++work_cnt;
     299             :                 /* may need to pause if we have done too much work in this
     300             :                  * loop */
     301           0 :                 if (work_cnt >= work_max_cnt) {
     302             :                         break;
     303             :                 }
     304           0 :         } while ((s = stream_fifo_head(mp->obuf)) != NULL);
     305           0 :         pim_msdp_write_proceed_actions(mp);
     306             : 
     307           0 :         if (PIM_DEBUG_MSDP_INTERNAL) {
     308           0 :                 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
     309             :                            mp->key_str, work_cnt);
     310             :         }
     311             : }
     312             : 
     313           0 : static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
     314             : {
     315             :         /* Add packet to the end of list. */
     316           0 :         pim_msdp_pkt_add(mp, s);
     317             : 
     318           0 :         PIM_MSDP_PEER_WRITE_ON(mp);
     319           0 : }
     320             : 
     321           0 : void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
     322             : {
     323           0 :         struct stream *s;
     324             : 
     325           0 :         if (mp->state != PIM_MSDP_ESTABLISHED) {
     326             :                 /* don't tx anything unless a session is established */
     327             :                 return;
     328             :         }
     329           0 :         s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
     330           0 :         stream_putc(s, PIM_MSDP_KEEPALIVE);
     331           0 :         stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
     332             : 
     333           0 :         pim_msdp_pkt_send(mp, s);
     334             : }
     335             : 
     336           0 : static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
     337             :                                              struct pim_msdp_peer *mp)
     338             : {
     339           0 :         struct stream *s;
     340             : 
     341           0 :         if (mp->state != PIM_MSDP_ESTABLISHED) {
     342             :                 /* don't tx anything unless a session is established */
     343             :                 return;
     344             :         }
     345           0 :         s = stream_dup(pim->msdp.work_obuf);
     346           0 :         if (s) {
     347           0 :                 pim_msdp_pkt_send(mp, s);
     348           0 :                 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
     349             :         }
     350             : }
     351             : 
     352             : /* push the stream into the obuf fifo of all the peers */
     353           0 : static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
     354             :                                  struct pim_msdp_peer *mp)
     355             : {
     356           0 :         struct listnode *mpnode;
     357             : 
     358           0 :         if (mp) {
     359           0 :                 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
     360             :         } else {
     361           0 :                 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
     362           0 :                         if (PIM_DEBUG_MSDP_INTERNAL) {
     363           0 :                                 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
     364             :                                            mp->key_str);
     365             :                         }
     366           0 :                         pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
     367             :                 }
     368             :         }
     369           0 : }
     370             : 
     371           0 : static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
     372             :                                     struct in_addr rp)
     373             : {
     374           0 :         int curr_tlv_ecnt;
     375             : 
     376           0 :         stream_reset(pim->msdp.work_obuf);
     377           0 :         curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
     378             :                                 ? PIM_MSDP_SA_MAX_ENTRY_CNT
     379             :                                 : local_cnt;
     380           0 :         local_cnt -= curr_tlv_ecnt;
     381           0 :         stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
     382           0 :         stream_putw(pim->msdp.work_obuf,
     383           0 :                     PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
     384           0 :         stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
     385           0 :         stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
     386             : 
     387           0 :         return local_cnt;
     388             : }
     389             : 
     390           0 : static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
     391             : {
     392           0 :         stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
     393           0 :         stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
     394           0 :         stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
     395           0 :         stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
     396           0 : }
     397             : 
     398           0 : static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
     399             :                                 struct pim_msdp_peer *mp)
     400             : {
     401           0 :         struct listnode *sanode;
     402           0 :         struct pim_msdp_sa *sa;
     403           0 :         int sa_count;
     404           0 :         int local_cnt = pim->msdp.local_cnt;
     405             : 
     406           0 :         sa_count = 0;
     407           0 :         if (PIM_DEBUG_MSDP_INTERNAL) {
     408           0 :                 zlog_debug("  sa gen  %d", local_cnt);
     409             :         }
     410             : 
     411           0 :         local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
     412             :                                              pim->msdp.originator_id);
     413             : 
     414           0 :         for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
     415           0 :                 if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
     416             :                         /* current implementation of MSDP is for anycast i.e.
     417             :                          * full mesh. so
     418             :                          * no re-forwarding of SAs that we learnt from other
     419             :                          * peers */
     420           0 :                         continue;
     421             :                 }
     422             :                 /* add sa into scratch pad */
     423           0 :                 pim_msdp_pkt_sa_fill_one(sa);
     424           0 :                 ++sa_count;
     425           0 :                 if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
     426           0 :                         pim_msdp_pkt_sa_push(pim, mp);
     427             :                         /* reset headers */
     428           0 :                         sa_count = 0;
     429           0 :                         if (PIM_DEBUG_MSDP_INTERNAL) {
     430           0 :                                 zlog_debug("  sa gen for remainder %d",
     431             :                                            local_cnt);
     432             :                         }
     433           0 :                         local_cnt = pim_msdp_pkt_sa_fill_hdr(
     434             :                                 pim, local_cnt, pim->msdp.originator_id);
     435             :                 }
     436             :         }
     437             : 
     438           0 :         if (sa_count) {
     439           0 :                 pim_msdp_pkt_sa_push(pim, mp);
     440             :         }
     441           0 :         return;
     442             : }
     443             : 
     444           0 : static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
     445             : {
     446           0 :         struct listnode *mpnode;
     447           0 :         struct pim_msdp_peer *mp;
     448             : 
     449             :         /* if SA were sent to the peers we restart ka timer and avoid
     450             :          * unnecessary ka noise */
     451           0 :         for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
     452           0 :                 if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
     453           0 :                         mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
     454           0 :                         pim_msdp_peer_pkt_txed(mp);
     455             :                 }
     456             :         }
     457           0 : }
     458             : 
     459           0 : void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
     460             : {
     461           0 :         pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
     462           0 :         pim_msdp_pkt_sa_tx_done(pim);
     463           0 : }
     464             : 
     465           0 : void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
     466             : {
     467           0 :         pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
     468           0 :         pim_msdp_pkt_sa_fill_one(sa);
     469           0 :         pim_msdp_pkt_sa_push(sa->pim, NULL);
     470           0 :         pim_msdp_pkt_sa_tx_done(sa->pim);
     471           0 : }
     472             : 
     473             : /* when a connection is first established we push all SAs immediately */
     474           0 : void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
     475             : {
     476           0 :         pim_msdp_pkt_sa_gen(mp->pim, mp);
     477           0 :         pim_msdp_pkt_sa_tx_done(mp->pim);
     478           0 : }
     479             : 
     480           0 : void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
     481             :                                         struct in_addr rp, pim_sgaddr sg)
     482             : {
     483           0 :         struct pim_msdp_sa sa;
     484             : 
     485             :         /* Fills the SA header. */
     486           0 :         pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
     487             : 
     488             :         /* Fills the message contents. */
     489           0 :         sa.pim = mp->pim;
     490           0 :         sa.sg = sg;
     491           0 :         pim_msdp_pkt_sa_fill_one(&sa);
     492             : 
     493             :         /* Pushes the message. */
     494           0 :         pim_msdp_pkt_sa_push(sa.pim, mp);
     495           0 :         pim_msdp_pkt_sa_tx_done(sa.pim);
     496           0 : }
     497             : 
     498           0 : static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
     499             : {
     500           0 :         pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
     501             : }
     502             : 
     503           0 : static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
     504             : {
     505           0 :         mp->ka_rx_cnt++;
     506           0 :         if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
     507           0 :                 pim_msdp_pkt_rxed_with_fatal_error(mp);
     508           0 :                 return;
     509             :         }
     510           0 :         pim_msdp_peer_pkt_rxed(mp);
     511             : }
     512             : 
     513           0 : static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
     514             : {
     515           0 :         int prefix_len;
     516           0 :         pim_sgaddr sg;
     517           0 :         struct listnode *peer_node;
     518           0 :         struct pim_msdp_peer *peer;
     519             : 
     520             :         /* just throw away the three reserved bytes */
     521           0 :         stream_get3(mp->ibuf);
     522           0 :         prefix_len = stream_getc(mp->ibuf);
     523             : 
     524           0 :         memset(&sg, 0, sizeof(sg));
     525           0 :         sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
     526           0 :         sg.src.s_addr = stream_get_ipv4(mp->ibuf);
     527             : 
     528           0 :         if (prefix_len != IPV4_MAX_BITLEN) {
     529             :                 /* ignore SA update if the prefix length is not 32 */
     530           0 :                 flog_err(EC_PIM_MSDP_PACKET,
     531             :                          "rxed sa update with invalid prefix length %d",
     532             :                          prefix_len);
     533           0 :                 return;
     534             :         }
     535           0 :         if (PIM_DEBUG_MSDP_PACKETS) {
     536           0 :                 zlog_debug("  sg %pSG", &sg);
     537             :         }
     538           0 :         pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
     539             : 
     540             :         /* Forwards the SA to the peers that are not in the RPF to the RP nor in
     541             :          * the same mesh group as the peer from which we received the message.
     542             :          * If the message group is not set, i.e. "default", then we assume that
     543             :          * the message must be forwarded.*/
     544           0 :         for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
     545             :                 /* Not a RPF peer, so skip it. */
     546           0 :                 if (pim_msdp_peer_rpf_check(peer, rp))
     547           0 :                         continue;
     548             :                 /* Don't forward inside the meshed group. */
     549           0 :                 if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
     550           0 :                     && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
     551           0 :                         continue;
     552             : 
     553           0 :                 pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
     554             :         }
     555             : }
     556             : 
     557           0 : static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
     558             : {
     559           0 :         int entry_cnt;
     560           0 :         int i;
     561           0 :         struct in_addr rp; /* Last RP address associated with this SA */
     562             : 
     563           0 :         mp->sa_rx_cnt++;
     564             : 
     565           0 :         if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
     566           0 :                 pim_msdp_pkt_rxed_with_fatal_error(mp);
     567           0 :                 return;
     568             :         }
     569             : 
     570           0 :         entry_cnt = stream_getc(mp->ibuf);
     571             :         /* some vendors include the actual multicast data in the tlv (at the
     572             :          * end). we will ignore such data. in the future we may consider pushing
     573             :          * it down the RPT
     574             :          */
     575           0 :         if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
     576           0 :                 pim_msdp_pkt_rxed_with_fatal_error(mp);
     577           0 :                 return;
     578             :         }
     579           0 :         rp.s_addr = stream_get_ipv4(mp->ibuf);
     580             : 
     581           0 :         if (PIM_DEBUG_MSDP_PACKETS) {
     582           0 :                 char rp_str[INET_ADDRSTRLEN];
     583           0 :                 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
     584           0 :                 zlog_debug("  entry_cnt %d rp %s", entry_cnt, rp_str);
     585             :         }
     586             : 
     587           0 :         pim_msdp_peer_pkt_rxed(mp);
     588             : 
     589           0 :         if (!pim_msdp_peer_rpf_check(mp, rp)) {
     590             :                 /* if peer-RPF check fails don't process the packet any further
     591             :                  */
     592           0 :                 if (PIM_DEBUG_MSDP_PACKETS) {
     593           0 :                         zlog_debug("  peer RPF check failed");
     594             :                 }
     595           0 :                 return;
     596             :         }
     597             : 
     598             :         /* update SA cache */
     599           0 :         for (i = 0; i < entry_cnt; ++i) {
     600           0 :                 pim_msdp_pkt_sa_rx_one(mp, rp);
     601             :         }
     602             : }
     603             : 
     604           0 : static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
     605             : {
     606           0 :         enum pim_msdp_tlv type;
     607           0 :         int len;
     608             : 
     609             :         /* re-read type and len */
     610           0 :         type = stream_getc_from(mp->ibuf, 0);
     611           0 :         len = stream_getw_from(mp->ibuf, 1);
     612           0 :         if (len < PIM_MSDP_HEADER_SIZE) {
     613           0 :                 pim_msdp_pkt_rxed_with_fatal_error(mp);
     614           0 :                 return;
     615             :         }
     616             : 
     617           0 :         if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
     618             :                 /* if tlv size if greater than max just ignore the tlv */
     619             :                 return;
     620             :         }
     621             : 
     622           0 :         if (PIM_DEBUG_MSDP_PACKETS) {
     623           0 :                 pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
     624             :         }
     625             : 
     626           0 :         switch (type) {
     627           0 :         case PIM_MSDP_KEEPALIVE:
     628           0 :                 pim_msdp_pkt_ka_rx(mp, len);
     629           0 :                 break;
     630           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE:
     631           0 :                 mp->sa_rx_cnt++;
     632           0 :                 pim_msdp_pkt_sa_rx(mp, len);
     633           0 :                 break;
     634           0 :         case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
     635             :         case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
     636             :         case PIM_MSDP_RESERVED:
     637             :         case PIM_MSDP_TRACEROUTE_PROGRESS:
     638             :         case PIM_MSDP_TRACEROUTE_REPLY:
     639           0 :                 mp->unk_rx_cnt++;
     640           0 :                 break;
     641             :         }
     642             : }
     643             : 
     644             : /* pim msdp read utility function. */
     645           0 : static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
     646             : {
     647           0 :         int nbytes;
     648           0 :         int readsize;
     649           0 :         int old_endp;
     650           0 :         int new_endp;
     651             : 
     652           0 :         old_endp = stream_get_endp(mp->ibuf);
     653           0 :         readsize = mp->packet_size - old_endp;
     654           0 :         if (!readsize) {
     655             :                 return 0;
     656             :         }
     657             : 
     658             :         /* Read packet from fd */
     659           0 :         nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
     660           0 :         new_endp = stream_get_endp(mp->ibuf);
     661           0 :         if (nbytes < 0) {
     662           0 :                 if (PIM_DEBUG_MSDP_INTERNAL) {
     663           0 :                         zlog_debug("MSDP peer %s read failed %d", mp->key_str,
     664             :                                    nbytes);
     665             :                 }
     666           0 :                 if (nbytes == -2) {
     667           0 :                         if (PIM_DEBUG_MSDP_INTERNAL) {
     668           0 :                                 zlog_debug(
     669             :                                         "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
     670             :                                         mp->key_str, old_endp, new_endp);
     671             :                         }
     672             :                         /* transient error retry */
     673           0 :                         return -1;
     674             :                 }
     675           0 :                 pim_msdp_pkt_rxed_with_fatal_error(mp);
     676           0 :                 return -1;
     677             :         }
     678             : 
     679           0 :         if (!nbytes) {
     680           0 :                 if (PIM_DEBUG_MSDP_INTERNAL) {
     681           0 :                         zlog_debug("MSDP peer %s read failed %d", mp->key_str,
     682             :                                    nbytes);
     683             :                 }
     684           0 :                 pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
     685           0 :                 return -1;
     686             :         }
     687             : 
     688             :         /* We read partial packet. */
     689           0 :         if (stream_get_endp(mp->ibuf) != mp->packet_size) {
     690           0 :                 if (PIM_DEBUG_MSDP_INTERNAL) {
     691           0 :                         zlog_debug(
     692             :                                 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
     693             :                                 mp->key_str, mp->packet_size, old_endp,
     694             :                                 new_endp);
     695             :                 }
     696           0 :                 return -1;
     697             :         }
     698             : 
     699             :         return 0;
     700             : }
     701             : 
     702           0 : void pim_msdp_read(struct thread *thread)
     703             : {
     704           0 :         struct pim_msdp_peer *mp;
     705           0 :         int rc;
     706           0 :         uint32_t len;
     707             : 
     708           0 :         mp = THREAD_ARG(thread);
     709           0 :         mp->t_read = NULL;
     710             : 
     711           0 :         if (PIM_DEBUG_MSDP_INTERNAL) {
     712           0 :                 zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
     713             :         }
     714             : 
     715           0 :         if (mp->fd < 0) {
     716             :                 return;
     717             :         }
     718             : 
     719             :         /* check if TCP connection is established */
     720           0 :         if (mp->state != PIM_MSDP_ESTABLISHED) {
     721           0 :                 pim_msdp_connect_check(mp);
     722           0 :                 return;
     723             :         }
     724             : 
     725           0 :         PIM_MSDP_PEER_READ_ON(mp);
     726             : 
     727           0 :         if (!mp->packet_size) {
     728           0 :                 mp->packet_size = PIM_MSDP_HEADER_SIZE;
     729             :         }
     730             : 
     731           0 :         if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
     732             :                 /* start by reading the TLV header */
     733           0 :                 rc = pim_msdp_read_packet(mp);
     734           0 :                 if (rc < 0)
     735             :                         return;
     736             : 
     737             :                 /* Find TLV type and len  */
     738           0 :                 stream_getc(mp->ibuf);
     739           0 :                 len = stream_getw(mp->ibuf);
     740           0 :                 if (len < PIM_MSDP_HEADER_SIZE) {
     741           0 :                         pim_msdp_pkt_rxed_with_fatal_error(mp);
     742           0 :                         return;
     743             :                 }
     744             : 
     745             :                 /*
     746             :                  * Handle messages with longer than expected TLV size: resize
     747             :                  * the stream to handle reading the whole message.
     748             :                  *
     749             :                  * RFC 3618 Section 12. 'Packet Formats':
     750             :                  * > ... If an implementation receives a TLV whose length
     751             :                  * > exceeds the maximum TLV length specified below, the TLV
     752             :                  * > SHOULD be accepted. Any additional data, including possible
     753             :                  * > next TLV's in the same message, SHOULD be ignored, and the
     754             :                  * > MSDP session should not be reset. ...
     755             :                  */
     756           0 :                 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
     757             :                         /* Check if the current buffer is big enough. */
     758           0 :                         if (mp->ibuf->size < len) {
     759           0 :                                 if (PIM_DEBUG_MSDP_PACKETS)
     760           0 :                                         zlog_debug(
     761             :                                                 "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
     762             :                                                 mp->key_str, len);
     763             : 
     764           0 :                                 stream_resize_inplace(&mp->ibuf, len);
     765             :                         }
     766             :                 }
     767             : 
     768             :                 /* read complete TLV */
     769           0 :                 mp->packet_size = len;
     770             :         }
     771             : 
     772           0 :         rc = pim_msdp_read_packet(mp);
     773           0 :         if (rc < 0)
     774             :                 return;
     775             : 
     776           0 :         pim_msdp_pkt_rx(mp);
     777             : 
     778             :         /* reset input buffers and get ready for the next packet */
     779           0 :         mp->packet_size = 0;
     780           0 :         stream_reset(mp->ibuf);
     781             : }

Generated by: LCOV version v1.16-topotato