tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_l3 / vde_l3.c
blob3c4f72ea20cd1a41752c41986e1f010238ddcbc9
1 /* VDE_ROUTER (C) 2007 Daniele Lacamera
3 * Licensed under the GPLv2
5 * This is a tiny v4 router that can be used to link
6 * together two or more vde switches.
8 */
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <getopt.h>
15 #include <errno.h>
16 #include <libgen.h>
17 #include <syslog.h>
18 #include <fcntl.h>
19 #include <time.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <sys/un.h>
29 #include <dlfcn.h>
31 #include <libvdeplug.h>
33 #include <config.h>
34 #include <vde.h>
35 #include <vdecommon.h>
36 #include "vde_buff.h"
37 #include "vde_l3.h"
40 #define MAXCMD 255
41 #define DEBUG 0
43 #if defined(VDE_FREEBSD) || defined(VDE_DARWIN)
44 #define ICMP_DEST_UNREACH 3
45 #define ICMP_PROT_UNREACH 2
46 #endif
49 * The main structure. Contains: interfaces, routing table,
50 * arp pending, etc.
52 struct vde_router VDEROUTER;
56 /* This is the default routing policy ( Unlimited fifo )
60 int ufifo_enqueue(struct vde_buff *vdb, struct vde_iface *vif)
62 struct vde_buff *qo = vif->q_out;
63 if (qo == NULL){
64 vif->q_out=vdb;
65 return 1;
67 while (qo->next!=NULL){
68 qo=qo->next;
70 qo->next = vdb;
71 return 1;
74 int ufifo_dequeue(struct vde_iface *vif){
75 struct vde_buff *vdb_out=vif->q_out;
76 raw_send(vif,vdb_out);
77 vif->q_out=vdb_out->next;
78 return (vif->q_out?1:0);
81 int ufifo_init(struct vde_iface *vif, char *args)
83 vif->policy_name = "ufifo";
84 return (strlen(args) == 0);
87 char *nostats(struct vde_iface *vif)
89 return "No Statistics Available.";
93 struct routing_policy unlimited_fifo_routing_policy ={
94 .name = "ufifo",
95 .help = "Unlimited FIFO (Default)\nUsage: tc set <dev> ufifo\n",
96 .enqueue = ufifo_enqueue,
97 .dequeue = ufifo_dequeue,
98 .tc_stats = nostats,
99 .policy_init = ufifo_init
103 inline struct vde_ethernet_header *ethhead(struct vde_buff *vdb)
105 return (struct vde_ethernet_header*)(vdb->data);
108 inline struct iphdr *iphead(struct vde_buff *vdb)
110 return (struct iphdr*)(vdb->data + 14);
113 inline void *payload(struct vde_buff *vdb)
115 return (uint8_t*)(vdb->data + 14 + sizeof(struct iphdr));
118 void *
119 tcpriv(struct vde_iface *vi)
121 return (void *)(vi->tc_priv);
124 void policy_register(struct routing_policy *r)
126 struct routing_policy *p = VDEROUTER.modlist;
127 if(p==NULL){
128 VDEROUTER.modlist = r;
129 return;
131 while (p->next!=NULL){
132 p=p->next;
134 r->next=NULL;
135 p->next=r;
138 struct routing_policy *getpolicy(char *name)
140 struct routing_policy *p = VDEROUTER.modlist;
141 struct routing_policy *new;
142 void *di;
143 char libname[300],libname2[300],libname3[300];
144 snprintf(libname,255,"%s.so",name);
145 snprintf(libname2,255,"/usr/lib/vde2/vde_l3/%s.so",name);
146 snprintf(libname3,255,"/usr/local/lib/vde2/vde_l3/%s.so",name);
148 while (p){
149 if (!strncmp(name,p->name,255))
150 return p;
151 p=p->next;
155 di = dlopen(libname,RTLD_LAZY);
156 if (di == NULL)
157 di = dlopen(libname2,RTLD_LAZY);
158 if (di == NULL)
159 di = dlopen(libname3,RTLD_LAZY);
161 if (di == NULL){
162 fprintf(stderr,"Error loading module %s: %s\n",libname,dlerror());
163 return NULL;
164 }else{
165 new = (struct routing_policy *) dlsym(di,"module_routing_policy");
166 if(new!=NULL){
167 policy_register(new);
168 return new;
169 }else{
170 fprintf(stderr,"Error registering module %s: %s\n",libname,dlerror());
171 return NULL;
178 void set_interface_policy (struct vde_iface *vif, struct routing_policy *rp)
180 vif->enqueue = rp->enqueue;
181 vif->dequeue = rp->dequeue;
183 if (rp->tc_stats)
184 vif->tc_stats = rp->tc_stats;
185 else
186 vif->tc_stats = nostats;
188 vif->policy_init = rp->policy_init;
193 static const int mgmtmode=0700;
194 static int max_total_sockets=0;
196 static char *progname;
199 /* Small utility functions, to talk to humans.
201 static char *ip2ascii(uint32_t ip){
202 struct in_addr ia_be;
203 ia_be.s_addr = htonl(ip);
204 return(strdup(inet_ntoa(ia_be)));
207 uint8_t *ip2mac(uint32_t ip)
209 uint8_t *ret =(uint8_t *) malloc(6);
210 uint32_t bigendian_ip = htonl(ip);
211 *ret = 0;
212 *(ret+1) = 0xAA;
213 memcpy(ret+2,&bigendian_ip,4);
214 return ret;
218 static char *mac2ascii(uint8_t *mac){
219 char *res = calloc(1,18);
220 snprintf(res,18,"%02X:%02X:%02X:%02X:%02X:%02X", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
221 return res;
226 * Get an interface from its id
228 static struct vde_iface *get_interface(int id){
229 struct vde_iface *ifc = VDEROUTER.interfaces;
230 while(ifc){
231 if(ifc->id == id)
232 return ifc;
233 ifc = ifc->next;
235 return NULL;
240 void usage(char *p)
242 fprintf(stderr,"Usage: %s [-G default_gw] -v vde_sock1:ipaddess1/netmask1 [-v ...] [-v vde_sockN:ipaddessN/netmaskN]\n",p);
243 fprintf(stderr," [-r network/netmask:gateway ] [-r ...] \n");
245 fprintf(stderr,"Options:\n");
246 fprintf(stderr,"-v VDESOCK:ADDRESS/NETMASK adds a network interface\n" \
247 "\twith address ADDRESS and netmask NETMASK. \n" \
248 "\tThe interface is connected to the vde socket VDESOCK.\n" \
249 "\t(At least one '-v' argument is required.)\n" \
250 "\n");
252 fprintf(stderr,"-r ADDRESS/NETMASK:GATEWAY adds a static route to the network\n" \
253 "\tADDRESS with netmask NETMASK, through the gateway GATEWAY. \n" \
254 "\n");
255 fprintf(stderr,"-G ADDRESS sets the router default gateway to ADDRESS.\n" \
256 "\n");
259 exit(1);
263 /* physically copy a vde_buff
265 struct vde_buff *buff_clone( struct vde_buff *orig)
267 struct vde_buff *clone = (struct vde_buff *)calloc(1,sizeof(struct vde_buff));
268 memcpy (clone,orig,sizeof(struct vde_buff));
269 clone->data = (char *)calloc(1,orig->len);
270 memcpy(clone->data,orig->data,orig->len);
271 return clone;
274 /**
275 * Send a packet directly using the ethernet
277 size_t raw_send(struct vde_iface *of,struct vde_buff *vdb)
279 #if(DEBUG)
280 fprintf(stderr,"Sending a %luB packet. VDECONN@%p. Protocol = %d through iface %d.\n",vdb->len,&(of->vdec),ntohs(*((uint16_t *)(vdb->data+12))),of->id);
281 #endif
282 return vde_send(of->vdec,vdb->data,vdb->len,0);
286 int ip_input(struct vde_buff *vdb);
287 int ip_output(struct vde_buff *vdb, uint32_t dst, uint8_t protocol);
288 size_t arp_query(struct vde_iface *oif, uint32_t tgt);
289 struct vde_iface *is_neightbor(uint32_t addr);
292 /* ip output wrapper
294 int ip_output_ready(struct vde_buff *vdb){
295 struct iphdr *iph = iphead(vdb);
296 return ip_output(vdb,ntohl(iph->daddr), iph->protocol);
299 /* List utilities
303 static struct vde_iface *add_iface(struct vde_iface *new, struct vde_iface *list)
305 if(list==NULL)
306 return new;
308 list->next=add_iface(new,list->next);
309 return list;
312 static struct vde_route *add_route(struct vde_route *new, struct vde_route *list)
314 if(list==NULL)
315 return new;
317 list->next=add_route(new,list->next);
318 return list;
321 static struct arp_entry *add_arp_entry(struct arp_entry *new, struct arp_entry *list)
323 if(list==NULL)
324 return new;
326 list->next=add_arp_entry(new,list->next);
327 return list;
331 /* Dequeue all pending packets that were
332 * waiting for arp IP/MAC association.
334 static void dequeue_pending(uint32_t addr)
336 struct vde_buff *pq = VDEROUTER.arp_pending;
337 struct vde_buff *tmp;
338 struct iphdr *h=iphead(pq);
339 if(ntohs(h->daddr) == addr){
340 ip_output(pq, addr, h->protocol);
341 VDEROUTER.arp_pending = pq->next;
343 while(pq->next){
344 h=iphead(pq->next);
345 if (h->daddr == addr) {
346 ip_output(pq->next,addr,h->protocol);
347 tmp=pq->next;
348 pq->next = tmp->next;
349 //free(tmp);
351 pq=pq->next;
356 * Get an arp entry from its ip.
358 static struct arp_entry *get_arp_entry(uint32_t ipaddr)
360 struct arp_entry *a=VDEROUTER.arp_table;
361 while (a){
362 if (a->ipaddr == ipaddr)
363 return a;
364 a = a->next;
366 return NULL;
370 /* Prepare a vde_buff to be sent through a local interface
372 int neightbor_send(struct vde_iface *to, struct vde_buff *vdb)
374 struct arp_entry *ae;
375 struct vde_ethernet_header *he;
376 struct iphdr *iph = iphead(vdb);
377 int packets_in = 0;
378 ae = get_arp_entry(iph->daddr);
379 he=ethhead(vdb);
380 if(ae){
381 memcpy(he->src,to->mac, 6);
382 memcpy(he->dst,ae->mac, 6);
383 packets_in = to->enqueue(vdb,to);
385 }else{
386 memset(he->src,0,6);
387 // VDEROUTER.arp_pending=enqueue(vdb,VDEROUTER.arp_pending);
388 arp_query(to, ntohl(iph->daddr));
390 return packets_in;
393 /* Prepare a vde_buff to be sent through a gateway
395 int gateway_send(struct vde_buff *vdb, uint32_t gw)
397 struct arp_entry *ae;
398 struct vde_ethernet_header *he;
399 struct vde_iface *to = is_neightbor(gw);
400 int packets_in = 0;
401 ae = get_arp_entry(htonl(gw));
402 he=ethhead(vdb);
403 if(ae){
404 memcpy(he->src,to->mac, 6);
405 memcpy(he->dst,ae->mac, 6);
406 packets_in = to->enqueue(vdb,to);
408 }else{
409 memset(he->dst, 0, 6);
410 // VDEROUTER.arp_pending=enqueue(vdb,VDEROUTER.arp_pending);
411 arp_query(to, gw);
414 return packets_in;
418 * Swap src/dst mac addresses at given mem addresses
420 static void swap_macaddr(uint8_t addr1[], uint8_t addr2[])
422 uint8_t tmp[6];
423 memcpy(tmp,addr1,6);
424 memcpy(addr1,addr2,6);
425 memcpy(addr2,tmp,6);
429 * Swap src/dst ip addresses at given mem addresses
431 static void swap_ipaddr(uint32_t *addr1, uint32_t *addr2)
433 uint32_t tmp;
434 memcpy(&tmp,addr1,4);
435 memcpy(addr1,addr2,4);
436 memcpy(addr2,&tmp,4);
440 /*****
441 * Allocate a new vde_buff packet of given size
443 static struct vde_buff *vdebuff_alloc(size_t size)
445 struct vde_buff *ret;
446 struct vde_ethernet_header *veh;
449 ret=(struct vde_buff *)calloc(1,sizeof(struct vde_buff));
450 // fprintf(stderr,"ALLOCATING %lu Bytes of memory: ",size);
451 ret->data=(char *)calloc(1,size+1);
452 if(ret==NULL || ret->data==NULL){
453 perror("Out of Memory.\n");
454 exit(1);
456 // fprintf(stderr,"Done.\n",size);
457 veh=ethhead(ret);
458 // Set default packet type (IP)
459 veh->buftype = htons(PTYPE_IP);
460 ret->len = size;
461 ret->next = NULL;
462 return ret;
465 /***
466 * Gets interface's mac address in a new array
468 static inline char *macaddr(struct vde_iface *vif)
470 char *mac=(char*)calloc(1,ETHERNET_ADDRESS_SIZE);
471 memcpy(mac,vif->mac,6);
472 return mac;
477 size_t vde_router_receive(struct vde_iface i)
480 return 0;
484 /* RFC 826 */
485 int is_arp_pending(struct vde_iface *of, uint8_t *mac){return 0;}
492 * Prepare and send an arp query
494 size_t arp_query(struct vde_iface *oif, uint32_t tgt)
496 struct vde_ethernet_header *vdeh;
497 struct arp_header *ah;
498 struct vde_buff *vdb;
500 /* Allocate 60B buffer for ARP request */
501 vdb = vdebuff_alloc(60);
503 /* populate eth header */
504 vdeh = ethhead(vdb);
505 memcpy(vdeh->dst, ETH_BCAST, 6);
506 memcpy(vdeh->src, oif->mac ,6);
507 vdeh->buftype = htons(PTYPE_ARP);
509 /* build arp payload */
510 ah =(struct arp_header *)iphead(vdb);
511 ah->htype = htons(HTYPE_ETH);
512 ah->ptype = htons(PTYPE_IP);
513 ah->hsize = ETHERNET_ADDRESS_SIZE;
514 ah->psize = IP_ADDRESS_SIZE;
515 ah->opcode = htons(ARP_REQUEST);
516 memcpy(ah->s_mac, oif->mac,6);
517 ah->s_addr = htonl(oif->ipaddr);
518 memset(ah->d_mac,0,6);
519 ah->d_addr = htonl(tgt);
521 return(raw_send(oif,vdb));
526 * Reply to given arp request, if needed
528 size_t arp_reply(struct vde_iface *oif, struct vde_buff *vdb)
530 struct vde_ethernet_header *vdeh;
531 struct arp_header *ah;
532 vdeh=ethhead(vdb);
533 swap_macaddr(vdeh->src,vdeh->dst);
534 memcpy(vdeh->src,oif->mac,6);
535 ah =(struct arp_header *)iphead(vdb);
536 ah->opcode = htons(ARP_REPLY);
537 swap_macaddr(ah->s_mac, ah->d_mac);
538 memcpy(ah->s_mac, oif->mac,6);
539 swap_ipaddr(&(ah->s_addr), &(ah->d_addr));
541 return(raw_send(oif,vdb));
546 /* Internet Protocol */
548 /* get the interface struct from its address
550 struct vde_iface *get_iface_by_ipaddr(uint32_t addr)
552 struct vde_iface *vif = VDEROUTER.interfaces;
553 while(vif){
554 if(vif->ipaddr == addr)
555 return vif;
556 vif = vif->next;
558 return NULL;
562 * Gets the interface through which we should be able to reach
563 * the given ip address. If the destination is not a neighbor,
564 * returns a NULL pointer.
566 struct vde_iface *is_neightbor(uint32_t addr)
568 struct vde_iface *vif = VDEROUTER.interfaces;
569 while(vif){
570 if((vif->ipaddr&vif->nm) == (addr&vif->nm))
571 return vif;
572 vif = vif->next;
574 return NULL;
580 * Returns the ip address of the gateway for this destination.
581 * If more than one route matches, the route with the stricter
582 * netmask is chosen.
584 uint32_t get_gateway(uint32_t addr)
586 struct vde_route *vdr = VDEROUTER.route_table;
587 uint32_t res = 0;
588 uint32_t max_netmask = 0;
589 while(vdr){
590 if((vdr->network & vdr->nm) == (addr & vdr->nm) && vdr->nm > max_netmask){
591 res = vdr->gw;
592 max_netmask = vdr->nm;
594 vdr = vdr->next;
596 if(!res)
597 return VDEROUTER.default_gw;
598 return res;
601 /* Parse an incoming arp packet */
602 int parse_arp(struct vde_buff *vdb)
604 struct arp_header *ah;
605 struct vde_iface *vif;
606 struct arp_entry *ae=(struct arp_entry*)malloc(sizeof(struct arp_entry));;
607 ah = (struct arp_header *)iphead(vdb);
608 vif = get_iface_by_ipaddr(ntohl(ah->d_addr));
609 if(!vif){
610 return -1;
612 memcpy(ae->mac,ah->s_mac,6);
613 ae->ipaddr=ah->s_addr;
615 VDEROUTER.arp_table = add_arp_entry(ae,VDEROUTER.arp_table);
616 switch(ntohs(ah->opcode)){
617 case ARP_REQUEST:
618 arp_reply(vif, vdb);
619 return 0;
620 case ARP_REPLY:
621 if(is_arp_pending(vif,ah->s_mac)){
622 dequeue_pending(ntohl(ah->s_addr));
623 return 0;
625 break;
627 return -1;
633 * Wrapper for neightbor/gateway send
635 * */
636 int ip_send(struct vde_buff *vdb)
638 struct vde_iface *oif;
639 struct iphdr *iph=iphead(vdb);
640 uint32_t gateway;
641 oif = is_neightbor(ntohl(iph->daddr));
642 if (oif!=NULL){
643 return neightbor_send(oif,vdb);
645 gateway = get_gateway(ntohl(iph->daddr));
646 if(gateway)
647 return gateway_send(vdb,gateway);
648 else
649 return -1;
653 * Forward the ip packet to next hop. TTL is decreased,
654 * checksum is set again for coherence, and TTL overdue
655 * packets are not forwarded.
657 int ip_forward(struct vde_buff *vdb){
658 struct iphdr *iph=iphead(vdb);
659 iph->ttl--;
660 iph->check++;
661 if(iph->ttl < 1)
662 return -1;
663 else
664 return ip_send(vdb);
667 /**
668 * Get a IP packet
670 int parse_ip(struct vde_buff *vdb)
672 struct vde_ethernet_header *eh;
673 struct iphdr *iph=iphead(vdb);
674 struct arp_entry *ae;
675 eh=ethhead(vdb);
677 if(!get_arp_entry(iph->saddr)){
678 ae=(struct arp_entry*)malloc(sizeof(struct arp_entry));;
679 memcpy(ae->mac,eh->src,6);
680 ae->ipaddr = iph->saddr;
681 VDEROUTER.arp_table = add_arp_entry(ae,VDEROUTER.arp_table);
683 if (get_iface_by_ipaddr(ntohl(iph->daddr))){
684 return ip_input(vdb);
685 }else{
686 return ip_forward(vdb);
691 * Calculate checksum of a given string
693 uint16_t checksum(uint8_t *buf, int len)
695 uint32_t sum = 0, carry=0;
696 int i=0;
697 for(i=0; i<len; i++){
698 if (i%2){
699 sum+=buf[i];
700 }else{
701 sum+=( buf[i] << 8);
704 carry = (sum&0xFFFF0000) >>16;
705 sum = (sum&0x0000FFFF);
706 return (uint16_t) ~(sum + carry) ;
710 * Calculate ip-header checksum. it's a wrapper for checksum();
712 uint16_t ip_checksum(struct iphdr *iph)
714 iph->check = 0U;
715 return checksum((uint8_t*)iph,sizeof(struct iphdr));
718 #define DEFAULT_TTL 64
721 * Layer 4 protocols should call this to transmit.
723 int ip_output(struct vde_buff *vdb, uint32_t dst, uint8_t protocol)
725 struct iphdr *iph=iphead(vdb);
726 struct vde_iface *oif;
727 memset(iph,0x45,1);
728 iph->tos = 0;
729 iph->frag_off=htons(0x4000); // Don't fragment.
730 iph->tot_len = htons(vdb->len - sizeof(struct vde_ethernet_header));
731 iph->id = 0;
732 iph->protocol = protocol;
733 iph->ttl = DEFAULT_TTL;
734 iph->check = htons(ip_checksum(iph));
736 oif = is_neightbor(dst);
737 if (!oif)
738 oif=is_neightbor(get_gateway(dst));
740 if(!oif){
741 #if DEBUG
742 fprintf(stderr, "Cannot determine the route to %08x",dst);
743 #endif
744 return -1;
748 iph->saddr = htonl(oif->ipaddr);
749 iph->daddr = htonl(dst);
750 iph->check = htons(ip_checksum(iph));
751 return ip_send(vdb);
754 /**
755 * Send a ICMP_PROTOCOL_UNREACHABLE if so.
758 static int service_unreachable(struct vde_buff *buf_in)
760 struct iphdr *iph_in;
761 struct icmp *ich;
762 struct vde_buff *vdb;
763 static uint16_t ident=0;
766 vdb=vdebuff_alloc(sizeof(struct vde_ethernet_header) +
767 sizeof(struct iphdr) + 8);
769 ich=(struct icmp *)payload(vdb);
770 ich->icmp_type = ICMP_DEST_UNREACH;
771 ich->icmp_code = ICMP_PROT_UNREACH;
772 ich->icmp_hun.ih_idseq.icd_id = ident++;
773 ich->icmp_hun.ih_idseq.icd_seq = 0;
774 if(ident == 0xFFFF)
775 ident = 0;
776 ich->icmp_cksum = 0;
777 ich->icmp_cksum = htons(checksum(payload(vdb), vdb->len - sizeof(struct iphdr) - 14));
779 iph_in = iphead(buf_in);
780 return ip_output(vdb,ntohl(iph_in->saddr),PROTO_ICMP);
784 /* Parse an incoming icmp packet
786 int parse_icmp(struct vde_buff *vdb)
788 struct icmp *ich;
789 struct iphdr *iph;
790 ich = (struct icmp *) payload(vdb);
791 iph = iphead(vdb);
792 if (ich->icmp_type == ICMP_ECHO){
793 swap_ipaddr(&iph->saddr,&iph->daddr);
794 ich->icmp_type = ICMP_ECHOREPLY;
795 ich->icmp_cksum = 0;
796 ich->icmp_cksum = htons(checksum(payload(vdb), vdb->len - 34));
797 iph->check = htons(ip_checksum(iph));
800 ip_output_ready(vdb);
801 return 1;
806 // Returns if the ip is unicast
807 static uint32_t inline unicast_ip(uint32_t ip){
808 if ((ip & 0xE0000000) == 0xE0000000)
809 return 0;
810 else
811 return ip;
815 uint32_t ascii2ip(char *c){
816 return (ntohl(inet_addr(c)));
819 //return >0 for valid netmasks.
820 uint32_t valid_nm(uint32_t nm)
822 int i=31;
823 uint32_t valid=0;
824 for (i=31; i>=0; i--){
825 valid+=(1<<i);
826 if(nm == valid)
827 return nm;
829 return 0;
832 uint32_t ascii2nm(char *c){
833 uint32_t res=ascii2ip(c);
834 int nmval=0,i=31;
835 if(!res){
836 if (sscanf(c,"%d",&nmval)<0){
837 return 0;
838 }else{
839 while(nmval>0 && nmval<32 && (i >= (32 - nmval)))
840 res+=(1<<i--);
843 return valid_nm(res);
846 //check if mac address is multicast
848 static int is_multicast_mac(uint8_t *mac)
850 if((mac[0]&0x01) && (mac[2]&0x5E))
851 return 1;
852 else return 0;
855 static void printoutc(int fd, const char *format, ...)
857 va_list arg;
858 char outbuf[MAXCMD+1];
860 va_start (arg, format);
861 vsnprintf(outbuf,MAXCMD,format,arg);
862 strcat(outbuf,"\n");
863 write(fd,outbuf,strlen(outbuf));
866 static int showinfo(int fd,char *s)
868 return -1;
871 static int help(int fd,char *s)
873 printoutc(fd, "help Display this inline help");
874 printoutc(fd, "ifconfig [vdN [ADDRESS [netmask NETMASK]]] Display virtual ethernet options/configure virtual ethernet N");
875 printoutc(fd, "route list Print out the routing table");
876 printoutc(fd, "route net ADDRESS/NETMASK gw GATEWAY Add static route");
877 printoutc(fd, "route default gw GATEWAY Add default route");
878 printoutc(fd, "tc ls Show each interface routing policy");
879 printoutc(fd, "tc set DEV POLICY ARGS Change interface routing policy");
880 printoutc(fd, "shutdown: shut the channel down");
881 printoutc(fd, "logout: log out from this mgmt session");
882 return 0;
886 static int route(int fd,char *s)
888 int arglen=strlen(s);
889 struct vde_iface *pi;
890 struct vde_route *pr;
891 s[arglen]='\0';
892 if(arglen==1){
893 goto routecmdfail;
896 //Route list
897 if(arglen == 5 && strncmp(s,"list",4)==0){
898 printoutc(fd,"Destination\tGateway\t\tGenmask\t\tIface");
899 pi = VDEROUTER.interfaces;
900 while(pi){
901 printoutc(fd,"%s\t%s\t\t%s\t\tvd%d",ip2ascii(pi->ipaddr&pi->nm),ip2ascii(0),ip2ascii(pi->nm),pi->id);
902 pi=pi->next;
904 pr = VDEROUTER.route_table;
905 while(pr){
906 pi=is_neightbor(pr->gw);
907 if(pi)
908 printoutc(fd,"%s\t%s\t\t%s\t\tvd%d",ip2ascii(pr->network&pr->nm),ip2ascii(pr->gw),ip2ascii(pr->nm),pi->id);
909 pr=pr->next;
911 pi=is_neightbor(VDEROUTER.default_gw);
912 if(VDEROUTER.default_gw)
913 printoutc(fd,"%s\t\t%s\t\t%s\t\tvd%d",ip2ascii(0),ip2ascii(VDEROUTER.default_gw),ip2ascii(0),pi->id);
915 //Route default
916 if(strncmp(s,"default gw ",11)==0){
917 VDEROUTER.default_gw = unicast_ip(ascii2ip(s+11));
918 if(!VDEROUTER.default_gw){
919 printoutc(fd,"Invalid gateway.");
920 goto routecmdfail;
922 printoutc(fd,"Default route changed to %s", ip2ascii(VDEROUTER.default_gw));
923 return 0;
925 //Route change/add
926 if(strncmp(s,"net ",4)==0){
927 char *addr,*nm,*gw;
928 struct vde_route *new = malloc (sizeof(struct vde_route));
929 addr=s+4;
930 if(!addr)
931 goto routecmdfail;
932 nm=index(addr,'/');
933 if(!nm)
934 goto routecmdfail;
935 *(nm++)=0;
936 gw=index(nm,':');
937 if(!gw)
938 goto routecmdfail;
939 *(gw++)=0;
940 new->network = unicast_ip(ascii2ip(addr));
941 new->gw = unicast_ip(ascii2ip(gw));
942 new->nm = ascii2nm(nm);
944 pr = VDEROUTER.route_table;
945 while(pr){
946 if(new->network == pr->network && new->nm == pr->nm){
947 pr->gw = new->gw;
948 printoutc(fd,"Route successfully updated.");
949 return 0;
951 pr = pr->next;
953 VDEROUTER.route_table = add_route(new, VDEROUTER.route_table);
954 printoutc(fd,"Route successfully added.");
957 return 0;
959 routecmdfail:
960 printoutc(fd, "'route' command usage:");
961 printoutc(fd, "route list Print out the routing table");
962 printoutc(fd, "route net ADDRESS/NETMASK:GATEWAY Add/change static route");
963 printoutc(fd, "route default gw GATEWAY Change default route");
965 return 1;
968 #define IF_SHALL 0
969 #define IF_SH1 1
970 #define IF_CHIP 2
971 #define IF_CHALL 3
974 static int if_display(int fd, char *iface){
975 struct vde_iface *pi;
976 int showone = 0;
977 int iface_id;
978 if(strncmp(iface,"all",3)==0){
979 pi=VDEROUTER.interfaces;
980 }else{
982 if(strncmp(iface,"vd",2)!=0){
983 return -1;
986 iface_id = atoi(iface+2);
987 pi = get_interface(iface_id);
988 if(!pi){
989 printoutc(fd, "Interface %s not found.",iface);
990 return -1;
992 showone = 1;
994 while(pi){
995 printoutc(fd, "vd%d\tLink encap: vde HWaddr %s",pi->id, mac2ascii(pi->mac));
996 printoutc(fd, "\tinet addr:%s Netmask:%s", ip2ascii(pi->ipaddr), ip2ascii(pi->nm));
997 printoutc(fd,"");
998 if(showone) return 0;
999 pi = pi->next;
1001 return 0;
1006 static int ifconfig(int fd, char *s)
1008 int arglen=strlen(s)-1;
1009 struct vde_iface *pi;
1010 char *addr,*nmtag,*nm=NULL,*iface;
1011 int iface_id;
1012 int mode;
1013 uint32_t tmp;
1015 s[arglen]='\0';
1016 if(arglen == 0){
1017 if(if_display(fd,"all") < 0)
1018 goto cmdfail;
1019 else
1020 return 0;
1023 iface=s;
1024 addr=index(iface,' ');
1025 if(!addr){
1026 if(if_display(fd,iface)<0)
1027 goto cmdfail;
1028 else
1029 return 0;
1032 *(addr++)=0;
1033 nmtag=index(addr,' ');
1034 if(!nmtag){
1035 mode=IF_CHIP;
1036 } else {
1037 *(nmtag++)=0;
1038 nm=index(nmtag,' ');
1039 if(!nm)
1040 goto cmdfail;
1041 *(nm++)=0;
1042 mode = IF_CHALL;
1045 if(strncmp(iface,"vd",2)!=0){
1046 goto cmdfail;
1049 iface_id = atoi(iface+2);
1050 pi = get_interface(iface_id);
1051 if(!pi){
1052 printoutc(fd, "Interface %s not found.",iface);
1053 goto cmdfail;
1056 tmp = unicast_ip(ascii2ip(addr));
1057 if(!tmp)
1058 goto cmdfail;
1059 pi->ipaddr = tmp;
1060 printoutc(fd, "IP address for %s successfully changed.",iface);
1061 if (mode == IF_CHALL){
1062 tmp = ascii2nm(nm);
1063 if(!tmp)
1064 goto cmdfail;
1065 pi->nm = tmp;
1066 printoutc(fd, "Netmask for %s successfully changed.",iface);
1068 return 0;
1070 cmdfail:
1071 printoutc(fd, "'ifconfig' command usage:");
1072 printoutc(fd, "ifconfig [vdN [ADDRESS [netmask NETMASK]]]");
1073 return 0;
1076 static int traffic_control(int fd, char *s)
1078 int arglen=strlen(s)-1;
1079 struct vde_iface *pi;
1080 struct routing_policy *pp;
1081 char *iface, *policy, *args;
1082 int ifnum;
1083 s[arglen]='\0';
1084 if(arglen==1){
1085 goto tccmdfail;
1088 //tc ls
1089 if (arglen == 2 && (strncmp(s,"ls",2)==0)){
1090 pi = VDEROUTER.interfaces;
1091 while (pi){
1092 printoutc(fd, "vd%d: %s. %s", pi->id, pi->policy_name, pi->tc_stats(pi));
1093 pi=pi->next;
1095 return 0;
1098 //tc set
1099 if (arglen > 4 && (strncmp(s,"set",3) == 0)){
1100 iface = s+4;
1101 policy=index(iface,' ');
1102 if(policy)
1103 *(policy++)=(char)0;
1104 if((strncmp(iface,"vd",2)) || (sscanf(iface+2,"%d",&ifnum)<1))
1105 goto tccmdfail;
1106 args=index(policy,' ');
1107 if(args){
1108 *(args++)=(char)0;
1109 }else{
1110 args="";
1113 if(strlen(policy)<1)
1114 goto tccmdfail;
1116 // check interface existstence
1117 pi = VDEROUTER.interfaces;
1118 while (pi && pi->id != ifnum){
1119 pi=pi->next;
1120 if (!pi){
1121 printoutc(fd, "tc: Device vd%d not found.",ifnum);
1122 goto tccmdfail;
1125 // try to get module
1126 pp=getpolicy(policy);
1127 if(!pp){
1128 printoutc(fd, "Cannot load rp module %s.so",policy);
1129 goto tccmdfail;
1130 }else{
1131 set_interface_policy(pi, pp);
1132 if (!pi->policy_init(pi,args)){
1133 printoutc(fd, "%s: syntax error.\n%s",pp->name,pp->help);
1134 goto tccmdfail;
1138 printoutc(fd, "vd%d: queuing discipline set to %s.", pi->id, pi->policy_name);
1139 return 0;
1142 tccmdfail:
1143 printoutc(fd, "'tc' command usage:");
1144 printoutc(fd, "tc ls Print out the routing policy for each interface");
1145 printoutc(fd, "tc set <DEV> <policy> <arguments> Change routing policy");
1146 return 0;
1150 static int logout(int fd,char *s)
1152 return -1;
1155 static int doshutdown(int fd,char *s)
1157 exit(0);
1161 #define WITHFD 0x80
1162 static struct comlist {
1163 char *tag;
1164 int (*fun)(int fd,char *arg);
1165 unsigned char type;
1166 } commandlist [] = {
1167 {"help", help, WITHFD},
1168 {"showinfo",showinfo, WITHFD},
1169 {"ifconfig",ifconfig, 0},
1170 {"route",route, 0},
1171 {"logout",logout, 0},
1172 {"shutdown",doshutdown, 0},
1173 {"tc",traffic_control,0}
1176 #define NCL sizeof(commandlist)/sizeof(struct comlist)
1178 static int handle_cmd(int fd,char *inbuf)
1180 int rv=ENOSYS;
1181 int i;
1182 while (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n') inbuf++;
1183 if (*inbuf != '\0' && *inbuf != '#') {
1184 for (i=0; i<NCL
1185 && strncmp(commandlist[i].tag,inbuf,strlen(commandlist[i].tag))!=0;
1186 i++)
1188 if (i<NCL)
1190 inbuf += strlen(commandlist[i].tag);
1191 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
1192 if (commandlist[i].type & WITHFD)
1193 printoutc(fd,"0000 DATA END WITH '.'");
1194 rv=commandlist[i].fun(fd,inbuf);
1195 if (commandlist[i].type & WITHFD)
1196 printoutc(fd,".");
1198 return rv;
1200 return rv;
1203 static char header[]="\nVDE Layer 3 Switch V.%s\n(C) D.Lacamera 2007 - GPLv2\n";
1204 static char prompt[]="\nVDE-L3$ ";
1206 static int mgmtcommand(int fd)
1208 char buf[MAXCMD+1];
1209 int n,rv;
1210 int outfd=fd;
1211 n = read(fd, buf, MAXCMD);
1212 if (n<0) {
1213 fprintf(stderr,"%s: read from mgmt %s",progname,strerror(errno));
1214 return -1;
1216 else if (n==0){
1217 return -1;
1218 /* Remote end has closed connection. */
1220 else {
1221 if (fd==STDIN_FILENO)
1222 outfd=STDOUT_FILENO;
1223 buf[n]=0;
1224 rv=handle_cmd(outfd,buf);
1225 if (rv>=0)
1226 write(outfd,prompt,strlen(prompt));
1227 return rv;
1231 static int delmgmtconn(int i,struct pollfd *pfd,int nfds)
1233 if (i<nfds) {
1234 close(pfd[i].fd);
1235 if (pfd[i].fd == 0) /* close stdin implies exit */
1236 exit(0);
1237 memmove(pfd+i,pfd+i+1,sizeof (struct pollfd) * (nfds-i-1));
1238 nfds--;
1240 return nfds;
1243 static int openmgmt(char *mgmt)
1245 int mgmtconnfd;
1246 struct sockaddr_un sun;
1247 int one = 1;
1249 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
1250 fprintf(stderr,"%s: mgmt socket: %s",progname,strerror(errno));
1251 exit(1);
1253 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
1254 sizeof(one)) < 0){
1255 fprintf(stderr,"%s: mgmt setsockopt: %s",progname,strerror(errno));
1256 exit(1);
1258 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
1259 fprintf(stderr,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname,strerror(errno));
1260 exit(1);
1262 sun.sun_family = PF_UNIX;
1263 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt);
1264 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
1265 fprintf(stderr,"%s: mgmt bind %s",progname,strerror(errno));
1266 exit(1);
1268 chmod(sun.sun_path,mgmtmode);
1269 if(listen(mgmtconnfd, 15) < 0){
1270 fprintf(stderr,"%s: mgmt listen: %s",progname,strerror(errno));
1271 exit(1);
1273 return mgmtconnfd;
1278 static int newmgmtconn(int fd,struct pollfd *pfd,int nfds)
1280 int new;
1281 unsigned int len=sizeof(struct sockaddr_un);
1282 char buf[MAXCMD];
1283 struct sockaddr addr;
1284 new = accept(fd, &addr, &len);
1285 if(new < 0){
1286 fprintf(stderr,"%s: mgmt accept %s",progname,strerror(errno));
1287 return nfds;
1289 if (nfds < max_total_sockets) {
1290 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
1291 write(new,buf,strlen(buf));
1292 write(new,prompt,strlen(prompt));
1293 pfd[nfds].fd=new;
1294 pfd[nfds].events=POLLIN | POLLHUP;
1295 return ++nfds;
1296 } else {
1297 fprintf(stderr,"%s: too many mgmt connections",progname);
1298 close (new);
1299 return nfds;
1304 int main(int argc, char *argv[])
1306 struct vde_iface *vif;
1307 struct pollfd *pfd, *pfdout;
1308 struct vde_buff *vdb_in, *vdb_out;
1309 struct vde_route *vr;
1310 int i,pr,pktin;
1311 int numif=0,npfd=0;
1312 struct vde_ethernet_header *eh;
1313 char *vdesock,*argp, *ipaddr, *nm=NULL, *gw, *mgmt=NULL;
1314 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
1315 int option_index;
1316 struct routing_policy *rp;
1318 int mgmtindex = -1;
1320 static struct option long_options[] = {
1321 {"help",0 , 0, 'h'},
1322 {"route",1 , 0, 'r'},
1323 {"defaultgw", 1, 0, 'G'},
1324 {"vdeplug", 1, 0, 'v'},
1325 {"mgmt", 1, 0, 'M'},
1326 //TODO {"daemon",0 , 0,'d'},
1328 progname=strdup(argv[0]);
1329 VDEROUTER.route_table = NULL;
1330 VDEROUTER.arp_table = NULL;
1331 VDEROUTER.arp_pending = NULL;
1332 VDEROUTER.modlist = NULL;
1333 VDEROUTER.default_gw = 0U;
1334 policy_register(&unlimited_fifo_routing_policy);
1336 while(1) {
1337 int c;
1338 c = GETOPT_LONG (argc, argv, "hM:r:G:v:",
1339 long_options, &option_index);
1340 if (c<0)
1341 break;
1342 switch (c) {
1343 case 'h':
1344 usage(progname);
1345 break;
1346 case 'M':
1347 mgmt=strdup(optarg);
1348 unlink(mgmt);
1349 break;
1350 case 'r':
1351 ipaddr=strdup(optarg);
1352 argp = index(ipaddr,'/');
1353 if(argp==NULL)
1354 usage(progname);
1355 *(argp++) = 0;
1356 gw = strdup(argp);
1357 argp = index(gw,':');
1358 if(argp==NULL)
1359 usage(progname);
1360 *(argp++) = 0;
1361 gw=strdup(argp);
1362 if (!gw)
1363 usage(progname);
1364 vr=(struct vde_route *)malloc(sizeof(struct vde_route));
1365 vr->network = unicast_ip(ascii2ip(ipaddr));
1366 vr->nm = ascii2nm(nm);
1367 vr->gw = unicast_ip(ascii2ip(gw));
1368 if(!vr->network){
1369 fprintf(stderr,"route: Cannot set network address to '%s'\n",ipaddr);
1370 usage(progname);
1372 if(!vr->nm){
1373 fprintf(stderr,"route: Cannot set netmask to '%s'\n",nm);
1374 if(nm!=NULL && nm[0]=='0'){
1375 fprintf(stderr,"(Did you mean to set default gateway? then -G)\n");
1377 usage(progname);
1379 if(!vr->gw){
1380 fprintf(stderr,"route: Cannot set gateway address to '%s'\n",gw);
1381 usage(progname);
1383 VDEROUTER.route_table = add_route(vr, VDEROUTER.route_table);
1384 break;
1386 case 'G':
1387 VDEROUTER.default_gw=unicast_ip(ascii2ip(optarg));
1388 if(!VDEROUTER.default_gw){
1389 fprintf(stderr,"Cannot set default gateway address to '%s'\n",optarg);
1390 usage(progname);
1392 break;
1393 case 'v':
1394 vdesock=strdup(optarg);
1395 argp = index(vdesock,':');
1396 if(argp==NULL)
1397 usage(progname);
1398 *(argp++) = 0;
1399 ipaddr = strdup(argp);
1400 argp = index(ipaddr,'/');
1401 if(argp==NULL)
1402 usage(progname);
1403 *(argp++) = 0;
1404 nm=strdup(argp);
1405 if (!nm)
1406 usage(progname);
1408 vif = (struct vde_iface *) malloc(sizeof (struct vde_iface));
1410 vif->vdec = vde_open(vdesock,"vde_L3",&open_args);
1411 if(!vif->vdec){
1412 fprintf(stderr,"vdeplug %s: %s\n",vdesock,strerror(errno));
1416 vif->ipaddr = unicast_ip(ascii2ip(ipaddr));
1417 if(!vif->ipaddr){
1418 fprintf(stderr,"vdeplug %s: Cannot set ip address to '%s'\n",vdesock,ipaddr);
1419 usage(progname);
1422 vif->nm = ascii2nm(nm);
1423 if(!vif->nm){
1424 fprintf(stderr,"vdeplug %s: Cannot set netmask to '%s'\n",vdesock,nm);
1425 if(nm!=NULL && nm[0]=='0'){
1426 fprintf(stderr,"(Did you mean to set default gateway? then -G)\n");
1428 usage(progname);
1431 vif->id=numif++;
1432 memcpy(vif->mac,ip2mac(vif->ipaddr),6);
1433 vif->q_in = NULL;
1434 vif->q_out = NULL;
1435 vif->next = NULL;
1436 rp = getpolicy("ufifo");
1437 if (!rp)
1438 fprintf(stderr,"Error getting policy ufifo: %s",dlerror());
1439 set_interface_policy(vif,rp);
1440 if(!vif->policy_init(vif,"")){
1441 fprintf(stderr,"Error setting default policy.\n");
1442 exit(1);
1445 VDEROUTER.interfaces = add_iface(vif, VDEROUTER.interfaces);
1446 break;
1448 default:
1449 usage(progname);
1450 break;
1453 if (optind < argc)
1454 usage(progname);
1455 if (!numif)
1456 usage(progname);
1457 max_total_sockets = numif + 4;
1458 pfd = (struct pollfd *) malloc ((max_total_sockets) * sizeof(struct pollfd));
1459 vif = VDEROUTER.interfaces;
1460 i=0;
1461 while (vif) {
1462 pfd[i].fd = vde_datafd(vif->vdec);
1463 pfd[i++].events=POLLIN | POLLHUP;
1464 vif = vif->next;
1466 npfd = numif;
1467 if(mgmt != NULL) {
1468 int mgmtfd=openmgmt(mgmt);
1469 mgmtindex=npfd;
1470 pfd[mgmtindex].fd=mgmtfd;
1471 pfd[mgmtindex].events=POLLIN | POLLHUP;
1472 npfd++;
1475 for(;;)
1477 pr = poll(pfd,npfd,10);
1478 if (pr < 0){
1479 perror("poll");
1480 exit(2);
1482 pktin = 0;
1483 if(pr > 0){
1484 for(i=0,vif=VDEROUTER.interfaces; i<numif && vif!=NULL; i++, vif = vif->next){
1485 if(pfd[i].revents == POLLIN){
1486 pr--;
1487 vdb_in=vdebuff_alloc(1550);
1488 if(!vdb_in)
1489 continue;
1490 vdb_in->len=vde_recv(vif->vdec,vdb_in->data,1548,0);
1491 #if(DEBUG)
1492 fprintf(stderr,"Rcvd a %luB packet. VDECONN@%p. Protocol = %d.\n",vdb_in->len,&(vif->vdec),ntohs(*((uint16_t *)(vdb_in->data+12))));
1493 #endif
1494 eh=ethhead(vdb_in);
1495 //Next line is a mac address filter.
1496 if((memcmp(eh->dst,vif->mac,6) == 0) || ((is_multicast_mac(eh->dst)) && (memcmp(eh->src,vif->mac,6)!=0))){
1497 if(eh->buftype == ntohs(PTYPE_ARP)){
1498 pktin += parse_arp(vdb_in);
1500 if(eh->buftype == ntohs(PTYPE_IP)){
1501 pktin += parse_ip(vdb_in);
1506 if (pr>0) { // if there are still events to handle (performance: packet switching first)
1507 int mgmtfdstart=numif;
1508 if (mgmtindex >= 0) {
1509 if (pfd[mgmtindex].revents != 0) {
1510 npfd=newmgmtconn(pfd[mgmtindex].fd,pfd,npfd);
1511 pr--;
1513 mgmtfdstart=mgmtindex+1;
1515 if (mgmtfdstart >= 0 && npfd > mgmtfdstart) {
1516 register int i;
1517 for (i=mgmtfdstart;i<npfd;i++) {
1518 if (pfd[i].revents & POLLHUP ||
1519 (pfd[i].revents & POLLIN && mgmtcommand(pfd[i].fd) < 0))
1520 npfd=delmgmtconn(i,pfd,npfd);
1521 if (pfd[i].revents) pr--;
1526 }// END POLLRET > 0
1527 int outqueues = 0, outloop = 0;
1528 pfdout = (struct pollfd *) malloc ((max_total_sockets) * sizeof(struct pollfd));
1529 vif=VDEROUTER.interfaces;
1530 while (vif){
1531 pfdout[outqueues].fd = vde_datafd(vif->vdec);
1532 pfdout[outqueues++].events = POLLOUT;
1533 vif = vif->next;
1536 vif=VDEROUTER.interfaces;
1537 if (poll(pfdout,outqueues,0) > 0){
1538 for(outloop = 0; outloop < outqueues; outloop++){
1539 if(pfdout[outloop].revents&POLLOUT && vif->q_out){
1540 vif->dequeue(vif);
1542 vif=vif->next;
1546 while(VDEROUTER.arp_pending){
1547 vdb_out=VDEROUTER.arp_pending;
1548 ip_output_ready(vdb_out);
1549 VDEROUTER.arp_pending=vdb_out->next;
1550 //free(vdb_out);
1556 * After being parsed, this is the point where packets
1557 * get to higher protocols
1559 int ip_input(struct vde_buff *vdb)
1562 struct iphdr *iph=iphead(vdb);
1563 if(*((uint8_t*)(iph)) != 0x45)
1564 return -1;
1565 switch(iph->protocol){
1566 case PROTO_ICMP:
1567 return parse_icmp(vdb);
1568 case PROTO_TCP:
1569 case PROTO_UDP:
1570 default:
1571 return service_unreachable(vdb);
1573 // return -1; // not reached