void tick() { if (m_transmit_on_receive && !m_new_packet) { // In this mode we only transmit if we got an packet return; } // We send a packet either: // 1) We are transmitting on receive and we got a packet // 2) We always transmit on every tick if (m_recode_on) { m_decoder->write_payload(&m_recode_buffer[0]); packet p(m_recode_buffer); p.set_sender(node_id()); forward_packet(p); } else { if (!m_last_packet.is_valid()) return; m_last_packet.set_sender(node_id()); forward_packet(m_last_packet); } m_new_packet = false; }
void create_replica(int node, oid_t id) { struct create_packet pc; struct write_packet pw; struct object_descriptor obj; void *buffer; read_metadata(id, &obj); buffer = malloc(obj.meta.size); read_data(&obj, 0, obj.meta.size, buffer); pc.obj = id; pc.type = obj.meta.type; strncpy((char*)pc.name, (const char*)obj.meta.name, 256); pw.obj = id; pw.offset = 0; pw.size = obj.meta.size; lock_object(id); pthread_mutex_lock(&peer_locks[node]); forward_packet(peer_srv_socks[node], OP_CREATE, OS_SLAVE, &pc, sizeof(pc)); receive_reply(peer_srv_socks[node], NULL, 0); forward_data(peer_srv_socks[node], OP_WRITE, OS_SLAVE, &pw, sizeof(pw), buffer, pw.size); receive_reply(peer_srv_socks[node], NULL, 0); pthread_mutex_unlock(&peer_locks[node]); unlock_object(id); free(buffer); }
void reqc_read(int sock, struct read_packet *p) { struct object_descriptor obj; void *buffer = malloc(p->size); int rsize; memset(buffer, 0, p->size); if (read_metadata(p->obj, &obj)) { rsize = read_data(&obj, p->offset, p->size, buffer); if (rsize >= 0) { send_reply(sock, buffer, rsize); free(buffer); return; } } for (unsigned int i = 0; i < peers.size(); i++) { pthread_mutex_lock(&peer_locks[i]); forward_packet(peer_srv_socks[i], OP_READ, OS_MASTER, p, sizeof(*p)); rsize = receive_reply(peer_srv_socks[i], buffer, p->size); pthread_mutex_unlock(&peer_locks[i]); if (rsize >= 0) { send_reply(sock, buffer, rsize); free(buffer); return; } } free(buffer); send_error(sock, ENOENT); }
void reqm_create(int sock, struct create_packet *p) { struct replica_info repl; int err, node = rand() % peers.size(); lock_object(p->dir_obj); lock_object(p->obj); err = create_object_mst(p->dir_obj, p->obj, (const char*)p->name, p->type); if (err) { unlock_object(p->dir_obj); unlock_object(p->obj); send_error(sock, err); return; } repl.id = p->obj; repl.node = node; pthread_mutex_lock(&replicas_lock); replicas.push_back(repl); pthread_mutex_unlock(&replicas_lock); pthread_mutex_lock(&peer_locks[node]); forward_packet(peer_srv_socks[node], OP_CREATE, OS_SLAVE, p, sizeof(*p)); receive_reply(peer_srv_socks[node], NULL, 0); pthread_mutex_unlock(&peer_locks[node]); unlock_object(p->dir_obj); unlock_object(p->obj); send_reply(sock, NULL, 0); }
void check_clients(fd_set *fds) { struct client_list **c; for (c = &clients; *c; ) { int next = 1; if (FD_ISSET((*c)->fd, fds)) { int len; const void *packet = read_sf_packet((*c)->fd, &len); if (packet) { forward_packet(packet, len); free((void *)packet); } else { rem_client(c); next = 0; } } if (next) c = &(*c)->next; } }
static void tcpip_handler(void) { /* char *str; uip_ipaddr_t tadd; printf("In tcphandler\n"); if(uip_newdata()) { str = uip_appdata; str[uip_datalen()] = '\0'; printf("DATA recv '%s'\n", str); //uip_ip6addr(&tadd, 0xaaaa, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202); //uip_udp_packet_sendto(client_conn, "from client ", sizeof("from client "), &tadd, UIP_HTONS(12345)); } */ uint8_t *appdata=NULL,a;int code=0; if(uip_newdata()) { appdata = (uint8_t *) uip_appdata; MAPPER_GET_PACKETDATA(code,appdata); switch(code) { case 1://helping packet printf("Helper message \n"); help(appdata); break; case 2://adding neighbor info and ranks forward_packet(appdata); break; case 3://victim packet printf("I am Victim\n"); monitoring(appdata); break; case 4://monitoring node break; case 5://Selent packet //upade_info(appdata); break; case 7://Nbr info req snd_nbr_info(); break; case 8://nbr_info process if(!attacker_set) select_attacker(appdata); break; case 9://Wormhole deactive MAPPER_GET_PACKETDATA(code,appdata); if(code==2) {printf("Attacker 2\n");attack_flag=1;attacker=2;setreg(17,0);} if(code==3) {printf("Attacker 3\n");attack_flag=1;attacker=3;dis_output(NULL);setreg(17,0);} break; } } }
void reqc_remove(int sock, struct remove_packet *p) { struct object_descriptor obj; int err; lock_object(p->dir_obj); lock_object(p->obj); if (read_metadata(p->obj, &obj)) { reqm_remove(sock, p, 1); return; } for (unsigned int i = 0; i < peers.size(); i++) { pthread_mutex_lock(&peer_locks[i]); forward_packet(peer_srv_socks[i], OP_REMOVE, OS_MASTER, p, sizeof(*p)); err = receive_reply(peer_srv_socks[i], NULL, 0); pthread_mutex_unlock(&peer_locks[i]); if (err >= 0) { unlock_object(p->dir_obj); unlock_object(p->obj); send_reply(sock, NULL, 0); return; } else if (err != -ENOENT) { unlock_object(p->dir_obj); unlock_object(p->obj); send_error(sock, -err); return; } } unlock_object(p->dir_obj); unlock_object(p->obj); send_error(sock, ENOENT); }
void reqm_remove(int sock, struct remove_packet *p, int unlock) { int err, node = -1; err = remove_object_mst(p->dir_obj, p->obj, p->type); if (err) { if (unlock) { unlock_object(p->dir_obj); unlock_object(p->obj); } send_error(sock, err); return; } pthread_mutex_lock(&replicas_lock); for (unsigned int i = 0; i < replicas.size(); i++) { if (!memcmp(&p->obj, &replicas[i].id, sizeof(oid_t))) { node = replicas[i].node; replicas.erase(replicas.begin() + i); break; } } pthread_mutex_unlock(&replicas_lock); if (node != -1) { pthread_mutex_lock(&peer_locks[node]); forward_packet(peer_srv_socks[node], OP_REMOVE, OS_SLAVE, p, sizeof(*p)); receive_reply(peer_srv_socks[node], NULL, 0); pthread_mutex_unlock(&peer_locks[node]); } if (unlock) { unlock_object(p->dir_obj); unlock_object(p->obj); } send_reply(sock, NULL, 0); }
int read_data_sch(const struct object_descriptor *descr, int offset, int size, void *buffer) { struct read_packet p; int res = io_read(descr, offset, size, buffer); if (res < 0) { p.obj = descr->id; p.offset = offset; p.size = size; for (unsigned int i = 0; i < peers.size(); i++) { pthread_mutex_lock(&peer_locks[i]); forward_packet(peer_srv_socks[i], OP_READ, OS_MASTER, &p, sizeof(p)); res = receive_reply(peer_srv_socks[i], buffer, size); pthread_mutex_unlock(&peer_locks[i]); if (res >= 0) return res; } } return res; }
int router_handle_packet(struct sr_instance* sr,uint8_t* ip_packet_start,int len,char* interface) { sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)ip_packet_start; /* Check if the above protocol is TCP/UDP or ICMP */ uint8_t protocol = ip_header->ip_p; if( protocol == TCP_PROTOCOL || protocol == UDP_PROTOCOL) { handle_ICMP(sr,ip_packet_start,len,3,3,interface,1); } else if( protocol == ICMP_PROTOCOL ) { /* Its an ICMP packet */ /* check if it is ICMP echo request or not */ uint16_t data_len = 0; uint8_t* data = 0; uint8_t* icmp_start = make_ICMP_packet_echo(ip_packet_start+sizeof(sr_ip_hdr_t),len-sizeof(sr_ip_hdr_t)); uint8_t* ip_start = make_IP_packet( *((uint8_t*)ip_header), ip_header->ip_tos, htons(len), \ ip_header->ip_id,ip_header->ip_off, 64, ip_header->ip_p, ip_header->ip_dst, ip_header->ip_src); uint8_t* final_packet = (uint8_t*)malloc(len); memcpy(final_packet,ip_start,sizeof(sr_ip_hdr_t)); memcpy(final_packet + sizeof(sr_ip_hdr_t),icmp_start,len-sizeof(sr_ip_hdr_t)); free(ip_start); free(icmp_start); /* print_hdr_icmp(final_packet+sizeof(sr_ip_hdr_t)); */ forward_packet(sr,final_packet,len,interface); } else { assert(0); } }
void handle_ICMP(struct sr_instance* sr,uint8_t* ip_packet_start,int len,short type,short code,char* interface,int to_router) { sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)ip_packet_start; /* No TCP/UDP stack running in the router */ /* Send ICMP Packet saying port unreachable */ /* Type = 3 and code = */ int size = sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8; uint8_t* complete_packet = (uint8_t*)malloc(size); uint8_t* icmp_pack = make_ICMP(sr,ip_packet_start,len,type,code); /* Get the interface to know the interface from where the ICMP TTL expored message should be sent */ struct sr_if* src_interface = sr_get_interface(sr,interface); uint32_t src_IP; if(type == 11) { src_IP = src_interface->ip; } else if(type == 3 && to_router == 1) { src_IP = ip_header->ip_dst; } else if(type == 3 && to_router == 0) { src_IP = src_interface->ip; } uint8_t* ip_pack = make_IP_packet(*((uint8_t*)ip_header),(0x0000), htons(size), 0x0000, 0x0000,64,0x01, \ /*ip_header->ip_dst*/src_IP,ip_header->ip_src); memcpy(complete_packet,ip_pack,sizeof(sr_ip_hdr_t)); memcpy(complete_packet+sizeof(sr_ip_hdr_t),icmp_pack,sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8); forward_packet(sr,complete_packet,size,interface); }
struct object_descriptor *read_metadata_sch(oid_t id, struct object_descriptor *descr) { struct getmeta_packet p; int err; if (!descr) descr = (struct object_descriptor *)malloc(sizeof(struct object_descriptor)); if (io_load_obj(id, descr) < 0) { p.obj = id; descr->id = id; for (unsigned int i = 0; i < peers.size(); i++) { pthread_mutex_lock(&peer_locks[i]); forward_packet(peer_srv_socks[i], OP_GETMETA, OS_MASTER, &p, sizeof(p)); err = receive_reply(peer_srv_socks[i], &descr->meta, sizeof(struct object_metadata)); pthread_mutex_unlock(&peer_locks[i]); if (err == sizeof(struct object_metadata)) return descr; } return NULL; } else return descr; }
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { /* Function implemented by g1izzyw and gustan50404 */ /* REQUIRES */ assert(sr); assert(packet); assert(interface); struct sr_if *ether_interface = (struct sr_if *) sr_get_interface(sr, interface); /* Check if it an ethernet interface. */ if (ether_interface) { /* Now we deal with the ethernet header */ struct sr_ethernet_hdr *ether_hdr = (struct sr_ethernet_hdr *) packet; /* Check to see if we are dealing with an ARP request/reply */ if (ether_hdr->ether_type == htons(ethertype_arp)) { fprintf(stderr, "We Got an ARP Packet\n"); /* Handle ARP for ethernet */ struct sr_arp_hdr * arp_hdr = (struct sr_arp_hdr *)(packet + sizeof(struct sr_ethernet_hdr)); if (arp_hdr->ar_hrd == htons(arp_hrd_ethernet)) { if (arp_hdr->ar_op == htons(arp_op_request)) { /* arp request */ struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip); if (interface_for_ip) { /* Target ip is one of the router interfaces */ fprintf(stderr, "ARP req for one of our interfaces\n"); /* Now we want to make an arp reply and send it back */ uint8_t *buf = (uint8_t *) malloc(len); memcpy(buf, packet, len); /*Make Arp Header*/ make_arprply_hdr(interface_for_ip->addr, arp_hdr->ar_sha, interface_for_ip->ip, arp_hdr->ar_sip, buf); /*Make Ethernet Header*/ make_ether_hdr(interface_for_ip->addr, ether_hdr->ether_shost, ethertype_arp, buf); /* Now we send the packet */ sr_send_packet(sr, buf, len, interface_for_ip->name); free(buf); fprintf(stderr, "ARP reply sent\n"); } } else if (arp_hdr->ar_op == htons(arp_op_reply)) { fprintf(stderr, "We got an ARP Reply, need to check for intfc tho \n"); /* arp reply */ struct sr_if *interface_for_ip = get_interface_for_ip(sr, arp_hdr->ar_tip); if (interface_for_ip) { fprintf(stderr, "We got an ARP Reply for one of our interfaces\n"); /*We first want to insert into Arp cache*/ struct sr_arpreq *request = sr_arpcache_insert(&(sr->cache), arp_hdr->ar_sha, arp_hdr->ar_sip); fprintf(stderr, "Signalling all waiting packets\n"); if (request) { struct sr_packet *cur_packet = request->packets; while(cur_packet) { fprintf(stderr, "About to forward \n"); print_hdrs(cur_packet->buf, cur_packet->len); forward_packet(sr, cur_packet->iface, arp_hdr->ar_sha, cur_packet->len, cur_packet->buf); fprintf(stderr, "Packet Forwarded\n"); cur_packet = cur_packet->next; } } } } } } else if (ether_hdr->ether_type == htons(ethertype_ip)) { /* Get the ip header from the ethernet header*/ sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t)); /*IP Checksum Stuff*/ uint16_t temp_ip_sum = ip_hdr->ip_sum; ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t)); if (temp_ip_sum == ip_hdr->ip_sum) { /*We got here means IP Cheksum is alright, so we extract the interface*/ struct sr_if *interface_for_ip = get_interface_for_ip(sr, ip_hdr->ip_dst); /*Check to make sure interface is one of ours*/ if (interface_for_ip) { fprintf(stderr, "IP Packet destined towards our interface\n"); /*Check if our IP packet is UDP or TCP*/ if (ip_hdr->ip_p == 6 || ip_hdr->ip_p == 17) { fprintf(stderr, "We Got TCP or UDP, sending ICMP error msg\n"); send_icmp_error(3, 3, sr, interface, len, packet); } else { /* Get the ICMP header */ sr_icmp_hdr_t *icmp_hdr = (struct sr_icmp_hdr *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)); /*Now we do the ICMP checksum chek*/ /*This covers the ICMP echo case*/ uint16_t temp_icmp_sum = icmp_hdr->icmp_sum; temp_icmp_sum = icmp_hdr->icmp_sum; icmp_hdr->icmp_sum = 0; if (temp_icmp_sum == cksum(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t), len - sizeof(sr_ethernet_hdr_t) - sizeof(sr_ip_hdr_t))) { /*Everything is fine so we send an ICMP echo back*/ fprintf(stderr, "Sending ICMP echo reply\n"); send_icmp_echo(sr, interface, len, packet); } } } else { /*IP Packet not destined towards one of our interfaces*/ fprintf(stderr, "IP packet not destined to our interface\n"); /*Decremenrt TTL by 1*/ fprintf(stderr, "TTL modified \n"); print_hdrs(packet, len); if (ip_hdr->ip_ttl <= 1) { fprintf(stderr, "Packte with TTL < 0 found, sending ICMP error \n"); /*TTL is less than 0 so send an ICMP ERROR*/ send_icmp_error(11, 0, sr, interface, len, packet); } else { /*Recompute Checksum over new header TTL is fine*/ /*Check if it exists in the routing table*/ ip_hdr->ip_ttl = ip_hdr->ip_ttl - 1; fprintf(stderr, "Recomputing Checksum after modifying TTl\n"); ip_hdr->ip_sum = 0; ip_hdr->ip_sum = cksum(packet + sizeof(sr_ethernet_hdr_t), sizeof(sr_ip_hdr_t)); struct sr_if *dst_if = (struct sr_if *)malloc(sizeof(struct sr_if)); dst_if = next_hop(sr, interface, ip_hdr->ip_dst); if (!(dst_if)) { fprintf(stderr, "IP packet has no longest matching prefix sending ICMP error\n"); /*dst ip has no longest macthing prefix*/ /*So we send a type 3 code 0 ICMP error*/ send_icmp_error(3, 0, sr, interface, len, packet); } else { /*This is the case where we do have a longest macthing prefix*/ fprintf(stderr, "Found Longest mathcing prefix in RT\n"); struct sr_arpcache *cache = &(sr->cache); struct sr_arpentry *in_cache = sr_arpcache_lookup(cache, ip_hdr->ip_dst); if (in_cache) { fprintf(stderr, "Found IP->MAC mapping in ARP cache forwarding packet \n"); /*this is the case where ip->mac maping is already in cache*/ forward_packet(sr, dst_if->name, in_cache->mac, len, packet); free(in_cache); } else { fprintf(stderr, "IP->MAC mapping not in ARP cache %u \n", ip_hdr->ip_dst); /*Case where ip->mapping is not in cache*/ sr_arpcache_queuereq(cache, ip_hdr->ip_dst, packet, len, dst_if->name); fprintf(stderr, "Added Arp Req to queu \n"); } } } } } } } } /* end sr_ForwardPacket */
void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { /* REQUIRES */ assert(sr); assert(packet); assert(interface); printf("*** -> Received packet of length %d \n",len); sr_ethernet_hdr_t* eth_header = (sr_ethernet_hdr_t*)packet; /* printf("The type is %x\n",ntohs(eth_header->ether_type));*/ if( ntohs(eth_header->ether_type) == IP_PROTOCOL) { /* Its an IP Packet */ printf("Its an IP Packet\n"); /* Check the checksum of the packet */ uint8_t* ip_packet = packet + sizeof(sr_ethernet_hdr_t); if(check_checksum(ip_packet,sizeof(sr_ip_hdr_t)) == 0) { /* Handle ICMP Error message */ return; } else { /* Checksum is fine, Now do the functions */ sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)ip_packet; /*print_hdr_ip(ip_packet);*/ if( decrement_TTL(ip_header) == 0 ) { /* Send ICMP packet for Time Limit Exceeded*/ ip_header->ip_sum = 0; ip_header->ip_ttl = 1; ip_header->ip_sum = cksum(ip_packet,sizeof(sr_ip_hdr_t)); /*make_ICMP_packet(); make_IP_packet();*/ /* Check wheather the Destination is this router */ if( check_match_all_interfaces ( sr->if_list, ip_header->ip_dst) == 1 ) { printf("I am here in TTL 0 \n\n\\n"); uint8_t protocol = ip_header->ip_p; if( protocol == TCP_PROTOCOL || protocol == UDP_PROTOCOL) { /* This is having UDP or TCP as payload */ /* So, just include this packet as payload and send the ICMP packet */ handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),3,3,interface,1); } else { /* Its ICMP protocol */ /* Check if it is echo request , If it is then send echo reply */ sr_icmp_hdr_t* icmp = (sr_icmp_hdr_t*)(ip_packet+sizeof(sr_ip_hdr_t)); if( icmp->icmp_type == 8 && icmp->icmp_code == 0) { int length = len - sizeof(sr_ethernet_hdr_t); uint8_t* data = 0; uint8_t* icmp_start = make_ICMP_packet_echo(ip_packet+sizeof(sr_ip_hdr_t),length-sizeof(sr_ip_hdr_t)); uint8_t* ip_start = make_IP_packet( *((uint8_t*)ip_header), ip_header->ip_tos, htons(length), \ ip_header->ip_id,ip_header->ip_off, 64, ip_header->ip_p,\ ip_header->ip_dst, ip_header->ip_src); uint8_t* final_packet = (uint8_t*)malloc(len); memcpy(final_packet,ip_start,sizeof(sr_ip_hdr_t)); memcpy(final_packet + sizeof(sr_ip_hdr_t),icmp_start,\ length-sizeof(sr_ip_hdr_t)); free(ip_start); free(icmp_start); forward_packet(sr,final_packet,length,interface); } else handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),11,0,interface,1); } } else { handle_ICMP(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),11,0,interface,0); } return; } /* Calculate new checksum after TTL updation */ ip_header->ip_sum = 0; ip_header->ip_sum = cksum(ip_packet,sizeof(sr_ip_hdr_t)); /*print_hdr_ip(ip_packet);*/ /* Check if the packet is destined to any of its interfaces */ /* Dont free this */ if( check_match_all_interfaces ( sr->if_list, ip_header->ip_dst) == 1 ) { /* Now its destined to router, so router should handle it It Should check for the Transport layer protocol and should appropriately send ICMP packets*/ router_handle_packet(sr,ip_packet,len-sizeof(sr_ethernet_hdr_t),interface); } else { /* Packet is subjected to NAT translation first and then forwarded 1) Check if there are any existing sessions for this packet, if any use them to translate the packets 2) If there aren't any, then allocate a new session and translate the packet. */ forward_packet(sr,ip_packet,len,interface); } } } else { printf("Its an ARP Packet\n"); /* Its an ARP Packet */ uint8_t* arp_packet = packet + sizeof(sr_ethernet_hdr_t); /* Construct ARP structure */ sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)arp_packet; /* Check if the packet is request to the router */ int dst_ip = ntohl(arp_header->ar_tip); struct sr_if* arp_interface = sr_get_interface(sr,interface); int interface_ip = ntohl(arp_interface->ip); if( dst_ip == interface_ip ) { /* It is destined correctly */ uint8_t op_code = ntohs(arp_header->ar_op); if( op_code == 1 ) { /* ARP Request */ uint8_t* arp_reply_packet; arp_reply_packet = (uint8_t*)malloc(sizeof(sr_ethernet_hdr_t)+1500); bzero(arp_reply_packet,sizeof(sr_ethernet_hdr_t)+1500); /* Create both ethernet and ARP structures */ sr_ethernet_hdr_t* new_eth = (sr_ethernet_hdr_t*)arp_reply_packet; /* Fill in all the details of ethernet frame */ memcpy(new_eth->ether_dhost,eth_header->ether_shost,sizeof(uint8_t)*6); memcpy(new_eth->ether_shost,arp_interface->addr,sizeof(uint8_t)*6); new_eth->ether_type = htons(ARP_PROTOCOL); /* Fill in all the details of ARP */ uint8_t* arp_reply_segment = arp_reply_packet+ sizeof(sr_ethernet_hdr_t); memcpy(arp_reply_segment,arp_packet,sizeof(sr_arp_hdr_t)); sr_arp_hdr_t* arp_reply_structure = (sr_arp_hdr_t*)arp_reply_segment; arp_reply_structure->ar_op = htons(2); memcpy(arp_reply_structure->ar_sha,arp_interface->addr,sizeof(uint8_t)*6); memcpy(arp_reply_structure->ar_tha,eth_header->ether_shost,sizeof(uint8_t)*6); arp_reply_structure->ar_sip = arp_interface->ip; arp_reply_structure->ar_tip = arp_header->ar_sip; /* Now send the packet */ /* Beaware of the size of the frame, it should not be sizeof(arp_reply_packet) But the size used below */ sr_send_packet(sr,arp_reply_packet,sizeof(sr_ethernet_hdr_t)+1500,interface); } else if( op_code == 2 ) { /* ARP Reply */ uint8_t* MAC = (uint8_t*)malloc(sizeof(uint8_t)*6); uint32_t IP; memcpy(MAC,arp_header->ar_sha,sizeof(uint8_t)*6); IP = arp_header->ar_sip; struct sr_arpreq* queue = sr_arpcache_insert(&sr->cache,MAC,IP); if( queue == NULL ) { assert(queue!=NULL); } else { struct sr_packet* packet_i = queue->packets; while( packet_i!= NULL ) { sr_ethernet_hdr_t* head = (sr_ethernet_hdr_t*)(packet_i->buf); memcpy(head->ether_dhost,MAC,sizeof(uint8_t)*6); sr_send_packet(sr,packet_i->buf,packet_i->len,packet_i->iface); packet_i = packet_i->next; } sr_arpreq_destroy(&sr->cache,queue); } } } } }/* end sr_ForwardPacket */
/* This will foreward the given IP packet It checks for the Destination IP address and finds appropriate interface (LPM) and sends out! */ int forward_packet(struct sr_instance* sr,uint8_t* packet,int len,int packet_src_iface) { uint32_t ip; sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)packet; /* Get Dest IP */ ip = ip_header->ip_dst; /* This target variable stores the next hop */ struct sr_rt* target = NULL; /* Perform LPM and get the target routing table entry which has the interface to pass and next hop IP */ target = LPM(sr->routing_table,ip); /* Now the next hop ip (dest->gw) is known and the interface also */ if( target == NULL ) { /* ICMP Destination Unreachable */ /* There is no routing table entry for this destination IP address Now we have to send this packet encapsulated in ICMP packet with 3,0( Destiantion Network Unreachable ) with src address of the incoming interface address and destination address as the source */ /* We have IP packet, Now encapsulate in the ICMP */ sr_icmp_hdr_t* ih = (sr_icmp_hdr_t*)(packet+sizeof(sr_ip_hdr_t)); if( (ip_header->ip_p == ICMP_PROTOCOL) && (ih->icmp_type != 8) ) { /* Dont send an ICMP for ICMP */ return; } print_hdr_ip(packet); int size = sizeof(sr_ip_hdr_t)+sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8; uint8_t* complete_packet = (uint8_t*) malloc(sizeof(uint8_t)*size); uint8_t* icmp_start = make_ICMP(sr,packet,len,3,0); struct sr_if* src_if = sr_get_interface(sr,packet_src_iface); uint8_t* ip_start = make_IP_packet(*((uint8_t*)ip_header),(0x0000), htons(size), 0x0000, 0x0000,64,0x01, \ src_if->ip,ip_header->ip_src); /* Foreward the ICMP packet with 3,0 to the src host */ /* If the entry is again wrong, then dont send the ICMP for ICMP */ memcpy(complete_packet,ip_start,sizeof(sr_ip_hdr_t)); memcpy(complete_packet+sizeof(sr_ip_hdr_t),icmp_start,sizeof(sr_icmp_hdr_t)+sizeof(sr_ip_hdr_t)+8); forward_packet(sr,complete_packet,size,packet_src_iface); return; } /* Now query for the Ethernet details */ /* Get the router interface from where the packet should leave */ struct sr_if* src_interface = sr_get_interface(sr,target->interface); /* Get the ARP entry for the next hop IP */ struct sr_arpentry* entry = sr_arpcache_lookup(&sr->cache,(target->gw.s_addr)); /* Now build the ethernet header */ uint8_t* complete_packet = (uint8_t*)malloc(sizeof(sr_ethernet_hdr_t)+len); memcpy(complete_packet+sizeof(sr_ethernet_hdr_t),packet,len); /* Fill in all the details of the ethernet */ sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*)complete_packet; memcpy(eth_hdr->ether_shost,src_interface->addr,sizeof(uint8_t)*6); eth_hdr->ether_type = htons(IP_PROTOCOL); /* If entry is NULL, It means that there is no cache entry in ARP Table */ /* If not NULL, Then use the entry for next hop MAC address */ /*assert(entry!=NULL);*/ if( entry == NULL ) { /* Destination MAC is not known ! */ memset(eth_hdr->ether_dhost,0,sizeof(uint8_t)*6); /* Cache doesnt have this entry, So request it */ struct sr_arpreq* req = sr_arpcache_queuereq(&sr->cache,target->gw.s_addr,complete_packet,len+sizeof(sr_ethernet_hdr_t) \ ,target->interface); assert(req!=NULL); /* Free the packet, as we dont need it. It has been copied to other buffer in the request queue */ handle_ARP_req(sr, &sr->cache,req); } else { /* Destination MAC is known, So use it! */ memcpy(eth_hdr->ether_dhost,entry->mac,sizeof(uint8_t)*6); /* Now send the packet to the target interface */ sr_send_packet(sr,complete_packet,sizeof(sr_ethernet_hdr_t)+len,target->interface); free(entry); } }
int main(int argc, char **argv) { int ch; uint32_t i; int rv; unsigned int iter = 0; glob_arg.ifname[0] = '\0'; glob_arg.output_rings = 0; glob_arg.batch = DEF_BATCH; glob_arg.syslog_interval = DEF_SYSLOG_INT; while ( (ch = getopt(argc, argv, "i:p:b:B:s:")) != -1) { switch (ch) { case 'i': D("interface is %s", optarg); if (strlen(optarg) > MAX_IFNAMELEN - 8) { D("ifname too long %s", optarg); return 1; } if (strncmp(optarg, "netmap:", 7) && strncmp(optarg, "vale", 4)) { sprintf(glob_arg.ifname, "netmap:%s", optarg); } else { strcpy(glob_arg.ifname, optarg); } break; case 'p': if (parse_pipes(optarg)) { usage(); return 1; } break; case 'B': glob_arg.extra_bufs = atoi(optarg); D("requested %d extra buffers", glob_arg.extra_bufs); break; case 'b': glob_arg.batch = atoi(optarg); D("batch is %d", glob_arg.batch); break; case 's': glob_arg.syslog_interval = atoi(optarg); D("syslog interval is %d", glob_arg.syslog_interval); break; default: D("bad option %c %s", ch, optarg); usage(); return 1; } } if (glob_arg.ifname[0] == '\0') { D("missing interface name"); usage(); return 1; } /* extract the base name */ char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ? glob_arg.ifname : glob_arg.ifname + 7; strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN); for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++) ; *nscan = '\0'; if (glob_arg.num_groups == 0) parse_pipes(""); setlogmask(LOG_UPTO(LOG_INFO)); openlog("lb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); uint32_t npipes = glob_arg.output_rings; pthread_t stat_thread; ports = calloc(npipes + 1, sizeof(struct port_des)); if (!ports) { D("failed to allocate the stats array"); return 1; } struct port_des *rxport = &ports[npipes]; init_groups(); if (pthread_create(&stat_thread, NULL, print_stats, NULL) == -1) { D("unable to create the stats thread: %s", strerror(errno)); return 1; } /* we need base_req to specify pipes and extra bufs */ struct nmreq base_req; memset(&base_req, 0, sizeof(base_req)); base_req.nr_arg1 = npipes; base_req.nr_arg3 = glob_arg.extra_bufs; rxport->nmd = nm_open(glob_arg.ifname, &base_req, 0, NULL); if (rxport->nmd == NULL) { D("cannot open %s", glob_arg.ifname); return (1); } else { D("successfully opened %s (tx rings: %u)", glob_arg.ifname, rxport->nmd->req.nr_tx_slots); } uint32_t extra_bufs = rxport->nmd->req.nr_arg3; struct overflow_queue *oq = NULL; /* reference ring to access the buffers */ rxport->ring = NETMAP_RXRING(rxport->nmd->nifp, 0); if (!glob_arg.extra_bufs) goto run; D("obtained %d extra buffers", extra_bufs); if (!extra_bufs) goto run; /* one overflow queue for each output pipe, plus one for the * free extra buffers */ oq = calloc(npipes + 1, sizeof(struct overflow_queue)); if (!oq) { D("failed to allocated overflow queues descriptors"); goto run; } freeq = &oq[npipes]; rxport->oq = freeq; freeq->slots = calloc(extra_bufs, sizeof(struct netmap_slot)); if (!freeq->slots) { D("failed to allocate the free list"); } freeq->size = extra_bufs; snprintf(freeq->name, MAX_IFNAMELEN, "free queue"); /* * the list of buffers uses the first uint32_t in each buffer * as the index of the next buffer. */ uint32_t scan; for (scan = rxport->nmd->nifp->ni_bufs_head; scan; scan = *(uint32_t *)NETMAP_BUF(rxport->ring, scan)) { struct netmap_slot s; s.buf_idx = scan; ND("freeq <- %d", s.buf_idx); oq_enq(freeq, &s); } if (freeq->n != extra_bufs) { D("something went wrong: netmap reported %d extra_bufs, but the free list contained %d", extra_bufs, freeq->n); return 1; } rxport->nmd->nifp->ni_bufs_head = 0; run: /* we need to create the persistent vale ports */ if (create_custom_ports(rxport->nmd->req.nr_arg2)) { free_buffers(); return 1; } atexit(delete_custom_ports); atexit(free_buffers); int j, t = 0; for (j = 0; j < glob_arg.num_groups; j++) { struct group_des *g = &groups[j]; int k; for (k = 0; k < g->nports; ++k) { struct port_des *p = &g->ports[k]; char interface[25]; sprintf(interface, "netmap:%s{%d/xT", g->pipename, g->first_id + k); D("opening pipe named %s", interface); p->nmd = nm_open(interface, NULL, 0, rxport->nmd); if (p->nmd == NULL) { D("cannot open %s", interface); return (1); } else { D("successfully opened pipe #%d %s (tx slots: %d)", k + 1, interface, p->nmd->req.nr_tx_slots); p->ring = NETMAP_TXRING(p->nmd->nifp, 0); } D("zerocopy %s", (rxport->nmd->mem == p->nmd->mem) ? "enabled" : "disabled"); if (extra_bufs) { struct overflow_queue *q = &oq[t + k]; q->slots = calloc(extra_bufs, sizeof(struct netmap_slot)); if (!q->slots) { D("failed to allocate overflow queue for pipe %d", k); /* make all overflow queue management fail */ extra_bufs = 0; } q->size = extra_bufs; snprintf(q->name, MAX_IFNAMELEN, "oq %s{%d", g->pipename, k); p->oq = q; } } t += g->nports; } if (glob_arg.extra_bufs && !extra_bufs) { if (oq) { for (i = 0; i < npipes + 1; i++) { free(oq[i].slots); oq[i].slots = NULL; } free(oq); oq = NULL; } D("*** overflow queues disabled ***"); } sleep(2); struct pollfd pollfd[npipes + 1]; memset(&pollfd, 0, sizeof(pollfd)); signal(SIGINT, sigint_h); while (!do_abort) { u_int polli = 0; iter++; for (i = 0; i < npipes; ++i) { struct netmap_ring *ring = ports[i].ring; if (nm_ring_next(ring, ring->tail) == ring->cur) { /* no need to poll, there are no packets pending */ continue; } pollfd[polli].fd = ports[i].nmd->fd; pollfd[polli].events = POLLOUT; pollfd[polli].revents = 0; ++polli; } pollfd[polli].fd = rxport->nmd->fd; pollfd[polli].events = POLLIN; pollfd[polli].revents = 0; ++polli; //RD(5, "polling %d file descriptors", polli+1); rv = poll(pollfd, polli, 10); if (rv <= 0) { if (rv < 0 && errno != EAGAIN && errno != EINTR) RD(1, "poll error %s", strerror(errno)); continue; } if (oq) { /* try to push packets from the overflow queues * to the corresponding pipes */ for (i = 0; i < npipes; i++) { struct port_des *p = &ports[i]; struct overflow_queue *q = p->oq; struct group_des *g = p->group; uint32_t j, lim; struct netmap_ring *ring; struct netmap_slot *slot; if (oq_empty(q)) continue; ring = p->ring; lim = nm_ring_space(ring); if (!lim) continue; if (q->n < lim) lim = q->n; for (j = 0; j < lim; j++) { struct netmap_slot s = oq_deq(q), tmp; tmp.ptr = 0; slot = &ring->slot[ring->cur]; if (slot->ptr && !g->last) { tmp.buf_idx = forward_packet(g + 1, slot); /* the forwarding may have removed packets * from the current queue */ if (q->n < lim) lim = q->n; } else { tmp.buf_idx = slot->buf_idx; } oq_enq(freeq, &tmp); *slot = s; slot->flags |= NS_BUF_CHANGED; ring->cur = nm_ring_next(ring, ring->cur); } ring->head = ring->cur; forwarded += lim; p->ctr.pkts += lim; } } int batch = 0; for (i = rxport->nmd->first_rx_ring; i <= rxport->nmd->last_rx_ring; i++) { struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i); //D("prepare to scan rings"); int next_cur = rxring->cur; struct netmap_slot *next_slot = &rxring->slot[next_cur]; const char *next_buf = NETMAP_BUF(rxring, next_slot->buf_idx); while (!nm_ring_empty(rxring)) { struct netmap_slot *rs = next_slot; struct group_des *g = &groups[0]; // CHOOSE THE CORRECT OUTPUT PIPE uint32_t hash = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B'); if (hash == 0) { non_ip++; // XXX ?? } rs->ptr = hash | (1UL << 32); // prefetch the buffer for the next round next_cur = nm_ring_next(rxring, next_cur); next_slot = &rxring->slot[next_cur]; next_buf = NETMAP_BUF(rxring, next_slot->buf_idx); __builtin_prefetch(next_buf); // 'B' is just a hashing seed rs->buf_idx = forward_packet(g, rs); rs->flags |= NS_BUF_CHANGED; rxring->head = rxring->cur = next_cur; batch++; if (unlikely(batch >= glob_arg.batch)) { ioctl(rxport->nmd->fd, NIOCRXSYNC, NULL); batch = 0; } ND(1, "Forwarded Packets: %"PRIu64" Dropped packets: %"PRIu64" Percent: %.2f", forwarded, dropped, ((float)dropped / (float)forwarded * 100)); } } } pthread_join(stat_thread, NULL); printf("%"PRIu64" packets forwarded. %"PRIu64" packets dropped. Total %"PRIu64"\n", forwarded, dropped, forwarded + dropped); return 0; }
int main(int argc, char *argv[]) { FILE *ft_output; char *filename; char line[MAXLINE]; unsigned int netsize; unsigned int ip[4]; int nic; unsigned int packet_id; router_state state; if (argc == 1) { filename = "fwd_table.txt"; } else { filename = argv[1]; if (!strcmp(filename, "-")) filename = "/dev/stdout"; } ft_output = fopen(filename, "w"); if (!ft_output) { perror("Could not open file for writing"); return 2; } state = initialize_router(); while(fgets(line, MAXLINE, stdin)) { if (toupper(line[0]) == 'T') { if (sscanf(line, "T %u.%u.%u.%u/%u %d", &ip[0], &ip[1], &ip[2], &ip[3], &netsize, &nic) < 6) fprintf(stderr, "Invalid table entry input: %s", line); else populate_forwarding_table(&state, ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3], netsize, nic); } else if (toupper(line[0]) == 'P') { if (sscanf(line, "P %u.%u.%u.%u %u", &ip[0], &ip[1], &ip[2], &ip[3], &packet_id) < 5) fprintf(stderr, "Invalid packet input: %s", line); else forward_packet(state, ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3], packet_id); } else if (toupper(line[0]) == 'A') { // Advertisements are output exactly as they are. This allows piping from part 2. printf("%s", line); } else { fprintf(stderr, "Invalid input line: %s\n", line); } } print_router_state(state, ft_output); destroy_router(state); fclose(ft_output); return EXIT_SUCCESS; }
/* * [emulate_nexthop] * Called per hop to advance through the hops in the path of the packet. * This is also called when there are no more hops or reuniting a * hdr with it's cached payload. */ void emulate_nexthop(struct packet *pkt) { int dropped; struct hop *curhop = *pkt->path; struct hop *prvhop = NULL; /* DEBUG */ if (pkt->info.hop==0){ /* first hop */ if (curhop->emulator){ printf("emulate_nxthop: hop=0, emulator!=NULL, srcip(0x%x) dstip(0x%x)\n", pkt->info.src, pkt->info.dst); printf(" It is likely that the routing table is corrupt.\n"); printf(" Or you're receiving stale VN traffic.\n"); /* drop */ MN_FREE_PKT(pkt); /* should never be cached at this point */ return; } } /* XTQ: if not on first hop && we're queueing bandwidth */ if (pkt->info.hop && (pkt->state & Q_BW)){ /* may have Q_DELAY set too */ prvhop = *(pkt->path - 1); /* ptr arithmetic */ if (!(pkt->state & Q_DELAY)){ /* Queueing BW & DELAY seperately */ if (prvhop->KBps) { update_bwq(prvhop);/* Update picture of the queue */ } /* * XTQ dequeue: Do I own the previous hop? */ if (MC_HOP_LOCAL(prvhop) && prvhop->xtq.dequeue){ Dprintf(("emulate_nexthop: xtq_dequeue\n"),P_XTQ); prvhop->xtq.dequeue(prvhop,pkt); } /* Schedule the delay */ pkt->state = Q_DELAY; TAILQ_INSERT_TAIL(packet_calendar + ((calendar_tick + prvhop->delay) & SCHEDMASK), pkt, list); return; } else { /* Queueing BW & DELAY together */ /* Fudged dequeue behavior. * XTQ dequeue: Do I own the previous hop? */ if (MC_HOP_LOCAL(prvhop) && prvhop->xtq.dequeue){ Dprintf(("emulate_nexthop: xtq_dequeue\n"),P_XTQ); prvhop->xtq.dequeue(prvhop,pkt); } } } /* At this point we're in one of 3 states * 1.) first hop, pkt->state = 0 * 2.) not first hop, pkt->state = Q_BW|Q_DELAY * Finished all delay. * 3.) not first hop, pkt->state = Q_DELAY * Finished all delay. * Do not need to reset pkt->state. */ /* forward_packet() * no more hops -> fwd to edge node * no more hops + pcache -> fwd to home core * reunited locally -> fwd to edge node */ if (!curhop) { forward_packet(pkt); MN_FREE_PKT(pkt); /* should never be cached at this point */ return; } Dprintf(("emulate_nexthop: pkt(0x%x) hop(%d)\n", (int) pkt, (int) pkt->info.hop), MN_P_PKTS); #if 0 if (!MC_HOP_LOCAL(curhop)) { printf("curhop->id(%d) emulator(%lu.%lu.%lu.%lu)\n", curhop->id, IP_ADDR_QUAD_N(curhop->emulator)); } #endif dropped = curhop->emulator ? remote_hop(pkt, curhop->emulator) : emulate_hop(pkt, curhop); /* * if it was a remote_hop, then this is a essentially a no-op * if it was a local hop, then it's on the delay queue or dropped */ ++pkt->path; ++pkt->info.hop; if (!(MC_PKT_HOME(pkt) && MC_PKT_PCACHED(pkt)) && (curhop->emulator)) { /* * if home and cached, then we can't free this pkt, if remote and * not home, then can free */ MN_FREE_PKT(pkt); } else if (dropped) { MN_FREE_PKT(pkt); } return; }
/* push the packet described by slot rs to the group g. * This may cause other buffers to be pushed down the * chain headed by g. * Return a free buffer. */ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs) { uint32_t hash = rs->ptr; uint32_t output_port = hash % g->nports; struct port_des *port = &g->ports[output_port]; struct netmap_ring *ring = port->ring; struct overflow_queue *q = port->oq; /* Move the packet to the output pipe, unless there is * either no space left on the ring, or there is some * packet still in the overflow queue (since those must * take precedence over the new one) */ if (nm_ring_space(ring) && (q == NULL || oq_empty(q))) { struct netmap_slot *ts = &ring->slot[ring->cur]; struct netmap_slot old_slot = *ts; uint32_t free_buf; ts->buf_idx = rs->buf_idx; ts->len = rs->len; ts->flags |= NS_BUF_CHANGED; ts->ptr = rs->ptr; ring->head = ring->cur = nm_ring_next(ring, ring->cur); port->ctr.pkts++; forwarded++; if (old_slot.ptr && !g->last) { /* old slot not empty and we are not the last group: * push it further down the chain */ free_buf = forward_packet(g + 1, &old_slot); } else { /* just return the old slot buffer: it is * either empty or already seen by everybody */ free_buf = old_slot.buf_idx; } return free_buf; } /* use the overflow queue, if available */ if (q == NULL || oq_full(q)) { /* no space left on the ring and no overflow queue * available: we are forced to drop the packet */ dropped++; port->ctr.drop++; return rs->buf_idx; } oq_enq(q, rs); /* * we cannot continue down the chain and we need to * return a free buffer now. We take it from the free queue. */ if (oq_empty(freeq)) { /* the free queue is empty. Revoke some buffers * from the longest overflow queue */ uint32_t j; struct port_des *lp = &ports[0]; uint32_t max = lp->oq->n; /* let lp point to the port with the longest queue */ for (j = 1; j < glob_arg.output_rings; j++) { struct port_des *cp = &ports[j]; if (cp->oq->n > max) { lp = cp; max = cp->oq->n; } } /* move the oldest BUF_REVOKE buffers from the * lp queue to the free queue */ // XXX optimize this cycle for (j = 0; lp->oq->n && j < BUF_REVOKE; j++) { struct netmap_slot tmp = oq_deq(lp->oq); oq_enq(freeq, &tmp); } ND(1, "revoked %d buffers from %s", j, lq->name); lp->ctr.drop += j; dropped += j; } return oq_deq(freeq).buf_idx; }