/* 11.2.A1: create a new peer and transition state to listen or connecting */ static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim, struct in_addr peer_addr, struct in_addr local_addr, const char *mesh_group_name, struct pim_msdp_peer **mp_p) { struct pim_msdp_peer *mp; pim_msdp_enable(pim); mp = XCALLOC(MTYPE_PIM_MSDP_PEER, sizeof(*mp)); mp->pim = pim; mp->peer = peer_addr; pim_inet4_dump("<peer?>", mp->peer, mp->key_str, sizeof(mp->key_str)); pim_msdp_addr2su(&mp->su_peer, mp->peer); mp->local = local_addr; /* XXX: originator_id setting needs to move to the mesh group */ pim->msdp.originator_id = local_addr; pim_msdp_addr2su(&mp->su_local, mp->local); mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; strlcpy(mp->last_reset, "-", sizeof(mp->last_reset)); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { mp->flags |= PIM_MSDP_PEERF_LISTENER; } /* setup packet buffers */ mp->ibuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE); mp->obuf = stream_fifo_new(); /* insert into misc tables for easy access */ mp = hash_get(pim->msdp.peer_hash, mp, hash_alloc_intern); listnode_add_sort(pim->msdp.peer_list, mp); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP peer %s created", mp->key_str); pim_msdp_peer_state_chg_log(mp); } /* fireup the connect state machine */ if (PIM_MSDP_PEER_IS_LISTENER(mp)) { pim_msdp_peer_listen(mp); } else { pim_msdp_peer_connect(mp); } if (mp_p) { *mp_p = mp; } return PIM_MSDP_ERR_NONE; }
/* RFC-3618:Sec-5.6 - stop the peer tcp connection and startover */ void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str) { if (PIM_DEBUG_EVENTS) { zlog_debug("MSDP peer %s tcp reset %s", mp->key_str, rc_str); snprintf(mp->last_reset, sizeof(mp->last_reset), "%s", rc_str); } /* close the connection and transition to listening or connecting */ pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); if (PIM_MSDP_PEER_IS_LISTENER(mp)) { pim_msdp_peer_listen(mp); } else { pim_msdp_peer_connect(mp); } }
/* RFC-3618:Sec-5.6 - connection retry on active peer */ static int pim_msdp_peer_cr_timer_cb(struct thread *t) { struct pim_msdp_peer *mp; mp = THREAD_ARG(t); if (PIM_DEBUG_MSDP_EVENTS) { pim_msdp_peer_timer_expiry_log(mp, "connect-retry"); } if (mp->state != PIM_MSDP_CONNECTING || PIM_MSDP_PEER_IS_LISTENER(mp)) { return 0; } pim_msdp_peer_active_connect(mp); return 0; }
/* passive peer socket accept */ static int pim_msdp_sock_accept(struct thread *thread) { union sockunion su; struct pim_instance *pim = THREAD_ARG(thread); int accept_sock; int msdp_sock; struct pim_msdp_peer *mp; char buf[SU_ADDRSTRLEN]; sockunion_init(&su); /* re-register accept thread */ accept_sock = THREAD_FD(thread); if (accept_sock < 0) { flog_err(LIB_ERR_DEVELOPMENT, "accept_sock is negative value %d", accept_sock); return -1; } pim->msdp.listener.thread = NULL; thread_add_read(master, pim_msdp_sock_accept, pim, accept_sock, &pim->msdp.listener.thread); /* accept client connection. */ msdp_sock = sockunion_accept(accept_sock, &su); if (msdp_sock < 0) { flog_err_sys(LIB_ERR_SOCKET, "pim_msdp_sock_accept failed (%s)", safe_strerror(errno)); return -1; } /* see if have peer config for this */ mp = pim_msdp_peer_find(pim, su.sin.sin_addr); if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) { ++pim->msdp.rejected_accepts; if (PIM_DEBUG_MSDP_EVENTS) { flog_err(PIM_ERR_MSDP_PACKET, "msdp peer connection refused from %s", sockunion2str(&su, buf, SU_ADDRSTRLEN)); } close(msdp_sock); return -1; } if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd >= 0 ? "(dup)" : ""); } /* if we have an existing connection we need to kill that one * with this one */ if (mp->fd >= 0) { if (PIM_DEBUG_MSDP_EVENTS) { zlog_notice( "msdp peer new connection from %s stop old connection", sockunion2str(&su, buf, SU_ADDRSTRLEN)); } pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); } mp->fd = msdp_sock; set_nonblocking(mp->fd); pim_msdp_update_sock_send_buffer_size(mp->fd); pim_msdp_peer_established(mp); return 0; }