/* Zebra client message read function. */ static int zclient_read (struct thread *thread) { size_t already; uint16_t length, command; uint8_t marker, version; struct zclient *zclient; /* Get socket to zebra. */ zclient = THREAD_ARG (thread); zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug ("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(zclient->ibuf, 0); /* Fetch header values. */ length = stream_getw (zclient->ibuf); marker = stream_getc (zclient->ibuf); version = stream_getc (zclient->ibuf); command = stream_getw (zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zclient->sock, marker, version); return zclient_failed(zclient); } if (length < ZEBRA_HEADER_SIZE) { zlog_err("%s: socket %d message length %u is less than %d ", __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); return zclient_failed(zclient); } /* Length check. */ if (length > STREAM_SIZE(zclient->ibuf)) { struct stream *ns; zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...", __func__, length, (u_long)STREAM_SIZE(zclient->ibuf)); ns = stream_new(length); stream_copy(ns, zclient->ibuf); stream_free (zclient->ibuf); zclient->ibuf = ns; } /* Read rest of zebra packet. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, length-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } } length -= ZEBRA_HEADER_SIZE; if (zclient_debug) zlog_debug("zclient 0x%p command 0x%x \n", (void *)zclient, command); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) (*zclient->ipv6_route_delete) (command, zclient, length); break; default: break; } if (zclient->sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ stream_reset(zclient->ibuf); zclient_event (ZCLIENT_READ, zclient); return 0; }
/* Handler of zebra service request. */ static int zebra_client_read (struct thread *thread) { int sock; struct zserv *client; size_t already; uint16_t length, command; uint8_t marker, version; /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD (thread); client = THREAD_ARG (thread); client->t_read = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } /* Read length and command (if we don't have it already). */ if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed socket [%d]", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(client->ibuf, 0); /* Fetch header values */ length = stream_getw (client->ibuf); marker = stream_getc (client->ibuf); version = stream_getc (client->ibuf); command = stream_getw (client->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, sock, marker, version); zebra_client_close (client); return -1; } if (length < ZEBRA_HEADER_SIZE) { zlog_warn("%s: socket %d message length %u is less than header size %d", __func__, sock, length, ZEBRA_HEADER_SIZE); zebra_client_close (client); return -1; } if (length > STREAM_SIZE(client->ibuf)) { zlog_warn("%s: socket %d message length %u exceeds buffer size %lu", __func__, sock, length, (u_long)STREAM_SIZE(client->ibuf)); zebra_client_close (client); return -1; } /* Read rest of data. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, length-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed [%d] when reading zebra data", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } } length -= ZEBRA_HEADER_SIZE; /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("zebra message comes from socket [%d]", sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug ("zebra message received [%s] %d", zserv_command_string (command), length); switch (command) { case ZEBRA_ROUTER_ID_ADD: zread_router_id_add (client, length); break; case ZEBRA_ROUTER_ID_DELETE: zread_router_id_delete (client, length); break; case ZEBRA_INTERFACE_ADD: zread_interface_add (client, length); break; case ZEBRA_INTERFACE_DELETE: zread_interface_delete (client, length); break; case ZEBRA_IPV4_ROUTE_ADD: zread_ipv4_add (client, length); break; case ZEBRA_IPV4_ROUTE_DELETE: zread_ipv4_delete (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_ROUTE_ADD: zread_ipv6_add (client, length); break; case ZEBRA_IPV6_ROUTE_DELETE: zread_ipv6_delete (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_REDISTRIBUTE_ADD: zebra_redistribute_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DELETE: zebra_redistribute_delete (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: zebra_redistribute_default_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: zebra_redistribute_default_delete (command, client, length); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_IPV4_IMPORT_LOOKUP: zread_ipv4_import_lookup (client, length); break; case ZEBRA_HELLO: zread_hello (client); break; default: zlog_info ("Zebra received unknown command %d", command); break; } if (client->t_suicide) { /* No need to wait for thread callback, just kill immediately. */ zebra_client_close(client); return -1; } stream_reset (client->ibuf); zebra_event (ZEBRA_READ, sock, client); return 0; }
int shim_sisis_read(struct thread * thread) { struct sisis_listener *listener; int sisis_sock; uint16_t length, command, checksum; int already; u_int ifindex; struct shim_interface * si; struct in6_addr src; char src_buf[INET6_ADDRSTRLEN]; struct in6_addr dst; char dst_buf[INET6_ADDRSTRLEN]; zlog_notice("Reading packet from SISIS connection!\n"); /* first of all get listener pointer. */ listener = THREAD_ARG (thread); sisis_sock = THREAD_FD (thread); if ((already = stream_get_endp(listener->ibuf)) < SV_HEADER_SIZE) { ssize_t nbytes; if (((nbytes = stream_read_try (listener->ibuf, sisis_sock, SV_HEADER_SIZE-already)) == 0) || (nbytes == -1)) { return -1; } if(nbytes != (SV_HEADER_SIZE - already)) { listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; } already = SV_HEADER_SIZE; } stream_set_getp(listener->ibuf, 0); /* read header packet. */ length = stream_getw (listener->ibuf); command = stream_getw (listener->ibuf); // will be 0 so may be discarded stream_get (&src, listener->ibuf, sizeof (struct in6_addr)); stream_get (&dst, listener->ibuf, sizeof (struct in6_addr)); ifindex = stream_getl(listener->ibuf); checksum = stream_getw(listener->ibuf); inet_ntop(AF_INET6, &src, src_buf, sizeof(src_buf)); inet_ntop(AF_INET6, &dst, dst_buf, sizeof(dst_buf)); zlog_debug("SISIS: length: %d, command: %d, ifindex: %d, checksum: %d sock %d, src: %s, dst: %s\n", length, command, ifindex, checksum, sisis_sock, src_buf, dst_buf); if(length > STREAM_SIZE(listener->ibuf)) { struct stream * ns; zlog_warn("message size exceeds buffer size"); ns = stream_new(length); stream_copy(ns, listener->ibuf); stream_free(listener->ibuf); listener->ibuf = ns; } if(already < length) { ssize_t nbytes; if(((nbytes = stream_read_try(listener->ibuf, sisis_sock, length-already)) == 0) || nbytes == -1) { return -1; } if(nbytes != (length-already)) { listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; } } length -= SV_HEADER_SIZE; switch(command) { case SV_JOIN_ALLSPF: zlog_debug("join allspf received"); shim_join_allspfrouters (ifindex); break; case SV_LEAVE_ALLSPF: zlog_debug("leave allspf received"); shim_leave_allspfrouters (ifindex); zlog_debug("index: %d\n", ifindex); break; case SV_JOIN_ALLD: zlog_debug("join alld received"); shim_join_alldrouters (ifindex); zlog_debug("index: %d", ifindex); break; case SV_LEAVE_ALLD: zlog_debug("leave alld received"); shim_leave_alldrouters (ifindex); zlog_debug("index: %d", ifindex); break; case SV_MESSAGE: zlog_debug("SISIS message received"); unsigned int num_of_addrs = number_of_sisis_addrs_for_process_type(SISIS_PTYPE_RIBCOMP_OSPF6); unsigned int num_of_listeners = number_of_listeners(); zlog_debug("num of listeners: %d, num of addrs: %d", num_of_listeners, num_of_addrs); float received_ratio = num_of_listeners/num_of_addrs; listener->chksum = checksum; if(received_ratio > (1/2)) { if(are_checksums_same()) { si = shim_interface_lookup_by_ifindex (ifindex); reset_checksums(); shim_send(&src, &dst, si, listener->ibuf, length); // shim_send(si->linklocal_addr, &dst, si, listener->ibuf, length); } else { zlog_notice("Checksums are not all the same"); } } else { zlog_notice("Not enough processes have sent their data: buffering ..."); } break; default: break; } if (sisis_sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ stream_reset(listener->ibuf); /* prepare for next packet. */ listener->thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; }
int shim_sisis_read(struct thread * thread) { struct sisis_listener *listener; int sisis_sock; uint16_t length, checksum; int already; u_int ifindex; struct shim_interface * si; struct in6_addr src; char src_buf[INET6_ADDRSTRLEN]; struct in6_addr dst; char dst_buf[INET6_ADDRSTRLEN]; zlog_notice("Reading packet from SISIS connection!"); /* first of all get listener pointer. */ listener = THREAD_ARG (thread); sisis_sock = THREAD_FD (thread); stream_reset(listener->ibuf); if ((already = stream_get_endp(listener->ibuf)) < SVZ_OUT_HEADER_SIZE) { ssize_t nbytes; if (((nbytes = stream_read_try (listener->ibuf, sisis_sock, SVZ_OUT_HEADER_SIZE-already)) == 0) || (nbytes == -1)) { return -1; } if(nbytes != (SVZ_OUT_HEADER_SIZE - already)) { listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; } already = SVZ_OUT_HEADER_SIZE; } stream_set_getp(listener->ibuf, 0); length = stream_getw(listener->ibuf); checksum = stream_getw(listener->ibuf); if(length > STREAM_SIZE(listener->ibuf)) { struct stream * ns; zlog_warn("message size exceeds buffer size"); ns = stream_new(length); stream_copy(ns, listener->ibuf); stream_free(listener->ibuf); listener->ibuf = ns; } if(already < length) { ssize_t nbytes; if(((nbytes = stream_read_try(listener->ibuf, sisis_sock, length-already)) == 0) || nbytes == -1) { return -1; } if(nbytes != (length-already)) { listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; } } unsigned int num_of_addrs = number_of_sisis_addrs_for_process_type(SISIS_PTYPE_RIBCOMP_OSPF6); unsigned int num_of_listeners = number_of_listeners(); zlog_notice("Number of addr: %d", num_of_addrs); zlog_notice("Number of listeners: %d", num_of_listeners); pthread_mutex_lock(&bmap_mutex); struct bmap * bmap = bmap_set(checksum); // if we added initially // set timer at which to recycle bmap // if there are no more processes sending data if(bmap->count == 0) { uint16_t * chcksum_ptr = malloc(sizeof(uint16_t)); *chcksum_ptr = checksum; listener->bmap_thread = thread_add_timer_msec (master, svz_sisis_clean_bmap, chcksum_ptr, 100); } bmap->count++; zlog_notice("# of streams %d for checksum %d with length %d", bmap->count, checksum, length); float received_ratio = (float)bmap->count/(float)num_of_addrs; stream_putw(listener->chksum_stream, checksum); if((received_ratio > 1.0/2.0) && !bmap->sent) { if(are_checksums_same()) { zlog_notice("Checksums are all the same"); if(primary_listener == NULL) primary_listener = listener; reset_checksum_streams(); svz_send(listener->ibuf); bmap->sent = 1; } else { zlog_notice("Checksums are not all the same"); stream_fifo_push(listener->dif, listener->ibuf); listener->dif_size++; } } else if(!bmap->sent) { zlog_notice("Not enough processes have sent their data; buffering..."); } else { zlog_notice("Data has already been sent..."); } if((bmap->count == num_of_addrs) && (bmap->sent)) { zlog_notice("Bmap no longer needed, freeing..."); bmap->count = 0; bmap->sent = 0; clear_checksum_streams(checksum); bmap_unset(checksum); } pthread_mutex_unlock(&bmap_mutex); if (sisis_sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ // stream_reset(listener->ibuf); /* prepare for next packet. */ listener->read_thread = thread_add_read (master, shim_sisis_read, listener, sisis_sock); return 0; }