/*--------------------------------------------------------------------------* * Author: Khaled Harfoush * * Last Updated: 4/30/2002 * * Functionality: An implementation of PeriScope user API for Linux. * * Applications should link with this library. * *--------------------------------------------------------------------------*/ #include #include #include #include #define MAX_n_replies 5000 #ifndef _PS_APP_H #define _PS_APP_H #include #include /* needs to agree with linux/include/net/PS.h */ #define SOCK_PS 7 #define IPPROTO_PS 7 /*used in setsockopt, agrees with include/linux/in.h */ #define PS_OPTIONS 15 /*--------------------------------------------------------------------------* * * * PeriScope Data Structures * * * *--------------------------------------------------------------------------*/ typedef struct flow_descr { int group_id; struct sockaddr *sa; int addr_len; void *buff; size_t buff_len; unsigned flags; } flow_descr_t; /*.........................................................................*/ typedef struct group_param { int group_id; int ctrl_fd; int max_phase; int probing_rate; int feedback_type; int feedback_rate; int cartouche_dimension; int delay; /* Delay inserted between probe packets: */ /* in order not to overflow host buffers, when connected to slow links */ } group_param_t; /*.........................................................................*/ typedef struct pkt_payload { /* payload that goes with the probes */ int group_id; int phase_no; int probe_packet_no; int probe_packet_tree_index; /* useful for topology characterization */ struct timeval probing_time; struct timeval feedback_time; } pkt_payload_t; /*.........................................................................*/ typedef struct probe_packet { int flow_id; int size; int TTL; } probe_packet_t; /*.........................................................................*/ typedef struct probe_structure { int group_id; int n_probe_packets; probe_packet_t *probe_packets; } probe_structure_t; /*.........................................................................*/ typedef struct flows_descr { int group_id; int num_flows; flow_descr_t *f_descr; } flows_descr_t; /*.........................................................................*/ typedef struct reorder_param { int group_id; int n_of_probes; } reorder_param_t; /*.........................................................................*/ typedef struct DOS_param{ /* DOS: ECHO REQUEST to node x and then ECHO REPLY to node y */ int group_id; int x; /* intermediate node */ int y; /* destination node */ int size; /* DOS packet size */ int id; } DOS_param_t; /*.........................................................................*/ typedef struct hop_count_param{ int group_id; int flow_id; int from; int to; int repetitions; } hop_count_param_t; /*.........................................................................*/ /*--------------------------------------------------------------------------* * * * IOCTL commands definitions mapped to the kernel * * * *--------------------------------------------------------------------------*/ #include int int_template; flow_descr_t flow_descr_template; flows_descr_t flows_descr_template; group_param_t group_param_template; probe_structure_t probe_structure_template; reorder_param_t reorder_param_template; DOS_param_t DOS_param_template; hop_count_param_t hop_count_param_template; #define PS_IOC_MAGIC 'Y' #define PS_SIOC_INIT _IO(PS_IOC_MAGIC,0) #define PS_SIOC_NEW_GROUP _IOWR(PS_IOC_MAGIC,1,group_param_template) #define PS_SIOC_REG_GROUP_PARAMS _IOWR(PS_IOC_MAGIC,2,group_param_template) #define PS_SIOC_REG_FLOW _IOWR(PS_IOC_MAGIC,3,flow_descr_template) #define PS_SIOC_REG_FLOWS _IOWR(PS_IOC_MAGIC,4,flows_descr_template) #define PS_SIOC_REG_PROB_STR _IOWR(PS_IOC_MAGIC,5,probe_structure_template) #define PS_SIOC_ACT_GROUP _IOW(PS_IOC_MAGIC,6,int_template) #define PS_SIOC_REORDER_TEST _IOW(PS_IOC_MAGIC,7,reorder_param_template) #define PS_SIOC_PROBE_TREE _IOW(PS_IOC_MAGIC,8,int_template) #define PS_SIOC_ACT_DOS _IOWR(PS_IOC_MAGIC,9,DOS_param_template) #define PS_SIOC_EST_HOP_COUNT _IOWR(PS_IOC_MAGIC,10,hop_count_param_template) #define PS_SIOC_CLOSE _IO(PS_IOC_MAGIC,11) #define PS_SIOCSETASSOC _IO(PS_IOC_MAGIC,12) #define PS_SIOCBULKNOTIFY _IO(PS_IOC_MAGIC,13) #define PS_SIOCACTCARTOUCHE _IO(PS_IOC_MAGIC,14) #define PS_SIOCTEST _IOW(PS_IOC_MAGIC,15,int_template) #define PS_SIOCDELASSOC _IO(PS_IOC_MAGIC,17) #define PS_SIOCSETCONGALG _IO(PS_IOC_MAGIC,18) #endif /*--------------------------------------------------------------------------* * * * PeriScope API Global Variables and Helper Functions * * * *--------------------------------------------------------------------------*/ typedef struct result_struct { int type; /* ECHO REQUEST or REPLY */ int phase_no; int tree_index; int packet_no; int TTL; int size; double k_departure; /* Departure timestamp collected in kernel */ double k_arrival; /* Arrival timestamp collected in the kernel */ double u_arrival; /* Arrival timestamp collected in user space */ } result_struct_t; char recvbuf[1500]; char sendbuf[1500]; struct icmp *icmp; pkt_payload_t *pl; int datalen=1400-8; /* number of data bytes in ICMP paylod */ probe_structure_t probe_structure; group_param_t group_param; hop_count_param_t hop_count_param; result_struct_t results_array[MAX_n_replies]; int n_replies=0; int tree_flag=0; struct iovec iovsend[1]; struct sockaddr *sarecv; int probing_rate=2; int max_phase=10; int delay=0; int nflows=0; int verbose=0; int ctrl_fd; int group_id; u_char *flows[100]; struct addrinfo *ai[50]; pid_t pid; int markers[2]; int markers_size[2]; double histogram_from=0.0; double histogram_step=50.0; double histogram_to=400.0; /*.........................................................................*/ void init_probe(int ctrl_fd){ int len; int size; pid_t pid; pid=getpid(); icmp=(struct icmp *)sendbuf; icmp->icmp_type=ICMP_ECHO; icmp->icmp_code=0; icmp->icmp_id=pid; icmp->icmp_seq=0; len=8+datalen; /*checksum ICMP header and data bytes*/ pl=(pkt_payload_t *)(sendbuf+8); pl->group_id=0; pl->phase_no=0; pl->probe_packet_no=0; gettimeofday(&(pl->probing_time),NULL); gettimeofday(&(pl->feedback_time),NULL); icmp->icmp_cksum=0; icmp->icmp_cksum=in_cksum((u_short *)icmp,len); size=128*1024; if (setsockopt(ctrl_fd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size))<0) printf("setsockopt error...\n"); if (setsockopt(ctrl_fd,SOL_SOCKET,SO_SNDBUF,&size,sizeof(size))<0) printf("setsockopt error...\n"); } /*.........................................................................*/ /*--------------------------------------------------------------------------* * * * PeriScope User Level API * * * *--------------------------------------------------------------------------*/ int PS_open(void){ /* * Creates a new control socket and returns its id. * PeriScope library uses this id to communicate with the kernel. */ int fd=-1; if ((fd=socket(AF_INET,SOCK_PS,IPPROTO_ICMP))==-1){ printf("Error PS_open: Not able to get a control socket...\n"); return -1; } ioctl(fd,PS_SIOC_INIT,NULL); init_probe(fd); return fd; /* Control file descriptor */ } /*.........................................................................*/ int PS_new_group(int ctrl_fd){ group_param.ctrl_fd=ctrl_fd; ioctl(ctrl_fd,PS_SIOC_NEW_GROUP,&group_param); if (group_param.group_id<0) printf("Error PS_new_group: Not able to create new group...\n"); return group_param.group_id; } /*.........................................................................*/ int PS_register_group_parameters(int ctrl_fd,int group_id){ group_param.ctrl_fd=ctrl_fd; group_param.group_id=group_id; ioctl(ctrl_fd,PS_SIOC_REG_GROUP_PARAMS,&group_param); if (group_param.group_id<0){ printf("Error PS_register_group_parameters: Not able to register...\n"); return group_param.group_id; } return 0; } /*.........................................................................*/ int PS_register_flow(int ctrl_fd, int group_id, u_char *host ) { /* register one flow for group group_id (adds to already registered flows) */ int err; flow_descr_t flowd; struct addrinfo *ai; ai=malloc(sizeof(struct addrinfo)); ai=host_serv(host,NULL,0,0); printf("REGISTER HOST %s (%s): %d data bytes\n",ai->ai_canonname, sock_ntop(ai->ai_addr,ai->ai_addrlen),datalen+8); if (ai->ai_family != AF_INET) printf("Unknown Address Family %d",ai->ai_family); flowd.group_id=group_id; flowd.sa=ai->ai_addr; flowd.addr_len=ai->ai_addrlen; flowd.buff=sendbuf; flowd.buff_len=datalen+8; /* ICMP header + data bytes */ flowd.flags=0; if ((err=ioctl(ctrl_fd,PS_SIOC_REG_FLOW,&flowd))<0) printf("Error PS_register_flow: Not able to register flow...\n"); return err; } /*.........................................................................*/ int PS_register_flows(int ctrl_fd, int group_id ) { /* register all the group_id group flows (removes already registered flows) */ /* Note that the passed parameters need to be optimized. I will come back */ /* to clean the flows parameters both in user and kernel space */ int err; flow_descr_t flowd; flows_descr_t flows_descr; struct addrinfo **ai; int i; ai=malloc(nflows*sizeof(struct addrinfo *)); flows_descr.group_id=group_id; flows_descr.num_flows=nflows; flows_descr.f_descr=malloc(nflows*sizeof(flow_descr_t)); for (i=0;iai_family != AF_INET) { printf("Unknown Address Family %d",ai[i]->ai_family); return -1; } printf("REGISTER HOST %s (%s): %d data bytes\n",ai[i]->ai_canonname, sock_ntop(ai[i]->ai_addr,ai[i]->ai_addrlen),datalen+8); flows_descr.f_descr[i].group_id=group_id; flows_descr.f_descr[i].sa=ai[i]->ai_addr; flows_descr.f_descr[i].addr_len=ai[i]->ai_addrlen; flows_descr.f_descr[i].buff=sendbuf; flows_descr.f_descr[i].buff_len=datalen+8; /* ICMP header + data bytes */ flows_descr.f_descr[i].flags=0; if ((err=ioctl(ctrl_fd,PS_SIOC_REG_FLOWS,&flows_descr))<0){ printf("Error PS_register_flow: Not able to register flow...\n"); return err; } } else return -1; } return 0; } /*.........................................................................*/ int PS_register_probe_structure(int ctrl_fd,int group_id) { int err; probe_structure.group_id=group_id; if ((err=ioctl(ctrl_fd,PS_SIOC_REG_PROB_STR,&probe_structure))<0) printf("Error PS_register_flow: Not able to register probe structure...\n"); return err; } /*.........................................................................*/ int PS_activate_group(int ctrl_fd, int group_id){ int err; setuid(getuid()); /* don't need special permissions anymore */ if ((err=ioctl(ctrl_fd,PS_SIOC_ACT_GROUP,&group_id))<0) printf("Error PS_activate_group: Not able to activate group...\n"); return err; } /*.........................................................................*/ int PS_activate_DOS(int ctrl_fd, DOS_param_t DOS_param){ int err; setuid(getuid()); /* don't need special permissions anymore */ if ((err=ioctl(ctrl_fd,PS_SIOC_ACT_DOS,&DOS_param))<0) printf("Error PS_activate_DOS: Not able to activate DOS...\n"); return err; } /*.........................................................................*/ int PS_reorder_test(int ctrl_fd, int group_id,int n_of_probes){ int err; reorder_param_t reorder_param; socklen_t len; ssize_t n,r; fd_set rset; int maxfdp1; double diff; struct timeval timeout; struct sockaddr *sarecv=calloc(1,16); int hlenl; pkt_payload_t *pl; struct ip *ip; struct icmp *icmp; int last_phase_no=0; int last_probe_packet_no=0; reorder_param.group_id=group_id; reorder_param.n_of_probes=n_of_probes; if ((err=ioctl(ctrl_fd,PS_SIOC_REORDER_TEST,&reorder_param))<0) { printf("Error PS_reorder_test: Not able to execute reorder test...\n"); return err; } printf("STARTING REORDER TEST...\n"); for (;;) { timeout.tv_sec=5; timeout.tv_usec=0; maxfdp1=ctrl_fd+1; FD_ZERO(&rset); FD_SET(ctrl_fd,&rset); if ((r=select(maxfdp1,&rset,NULL,NULL,&timeout))==0){ printf("REORDER TEST DONE..."); if (err) printf("FAILED...\n"); else printf("SUCCEEDED...\n"); goto over; } len=16; n=recvfrom(ctrl_fd,recvbuf,sizeof(recvbuf),0,sarecv,&len); if (n<0) { if (errno==EINTR) continue; else { printf("recvfrom error...\n"); exit(1); } } ip=(struct ip *)recvbuf; hlenl=ip->ip_hl << 2; icmp=(struct icmp *)(recvbuf+hlenl); if (icmp->icmp_type == ICMP_ECHOREPLY) { pl=(pkt_payload_t *)(recvbuf+hlenl+8); printf("(%d,%d) (%d bytes %s)\n", pl->phase_no,pl->probe_packet_no,n,sock_ntop(sarecv,len)); if ((pl->phase_nophase_no==last_phase_no) &&(pl->probe_packet_nophase_no; last_probe_packet_no=pl->probe_packet_no; } } } over: return err; } /*.........................................................................*/ int PS_probe_tree(int ctrl_fd, int group_id){ int err; setuid(getuid()); /* don't need special permissions anymore */ if ((err=ioctl(ctrl_fd,PS_SIOC_PROBE_TREE,&group_id))<0){ printf("Error PS_probe_tree: Not able to probe tree...\n"); printf("Make sure to have at least 2 flows and flows 0,1 in the probe structure...\n"); } return err; } /*.........................................................................*/ int PS_est_hop_count(int ctrl_fd){ int err; setuid(getuid()); /* don't need special permissions anymore */ if ((err=ioctl(ctrl_fd,PS_SIOC_EST_HOP_COUNT,&hop_count_param))<0){ printf("Error PS_est_hop_count Not able to estimate hop count...\n"); } return err; } /*.........................................................................*/ int PS_close(int ctrl_fd) { /* * Close and clean up flow state. */ // ioctl(ctrl_fd,PS_SIOC_CLOSE,NULL); return close(ctrl_fd); } /*.........................................................................*/