On Wed, 14 Sep 2005, Jeff Haran wrote: > Hmmm... Two days go by and not a single response to this (at least I > haven't seen any). > > I would have thought that a mailing list named linux-net would be > interested in possible linux networking stack problems. > > Is this the wrong mailing list to post something like this to? Please use netdev@xxxxxxxxxxxxxxx for Linux networking development issues. > Thanks, > > Jeff Haran > > > -----Original Message----- > > From: linux-net-owner@xxxxxxxxxxxxxxx > > [mailto:linux-net-owner@xxxxxxxxxxxxxxx]On Behalf Of Jeff Haran > > Sent: Monday, September 12, 2005 3:11 PM > > To: linux-net@xxxxxxxxxxxxxxx > > Subject: kernel bug? - routing table entry lost > > > > > > Hi all, > > > > I've been experimenting with the configuration of IP aliases > > on a 2.4.19 based kernel and have run across some behavior > > that I suspect is a bug, but am wondering if perhaps I am > > just doing something wrong. > > > > In summary, what I find is that if I start with an interface > > that is configured with a single IP address, then add a > > secondary IP address to that interface and then delete that > > secondary IP address so that I am now presumably back where I > > started, one of the internal routes generated by the kernel > > disappears. > > > > To get visibility into this, I wrote a program (adopted from > > some code I found on another site) that sends a RTM_GETROUTE > > message to a NETLINK_ROUTE socket and then reads and displays > > the response from the kernel. That program is called > > route_get in the logs that follow and I've copied the source > > to route_get to the end of email. > > > > The annotated console log that demonstrates the problem > > follows. I start with interfaces down and no IP addresses assigned: > > > > FD21:root> ip -s -s link show > > 1: lo: <LOOPBACK> mtu 16436 qdisc noop > > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 > > RX: bytes packets errors dropped overrun mcast > > 0 0 0 0 0 0 > > RX errors: length crc frame fifo missed > > 0 0 0 0 0 > > TX: bytes packets errors dropped carrier collsns > > 0 0 0 0 0 0 > > TX errors: aborted fifo window heartbeat > > 0 0 0 0 > > 2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 100 > > link/ether 00:60:69:90:02:7a brd ff:ff:ff:ff:ff:ff > > RX: bytes packets errors dropped overrun mcast > > 0 0 0 0 0 0 > > RX errors: length crc frame fifo missed > > 0 0 0 0 0 > > TX: bytes packets errors dropped carrier collsns > > 0 0 0 0 0 0 > > TX errors: aborted fifo window heartbeat > > 0 0 0 0 > > FD21:root> ip -s -s addr show > > 1: lo: <LOOPBACK> mtu 16436 qdisc noop > > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 > > 2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 100 > > link/ether 00:60:69:90:02:7a brd ff:ff:ff:ff:ff:ff > > > > So now I configure eth0 up, but still with no addresses: > > > > FD21:root> ip link set dev eth0 up > > FD21:root> eth0: Link status change: Link Up. 100 Mbps Half > > duplex Auto (autonegotiation complete). > > > > I add the first IP address and run my route_get program to > > see the resultant routes: > > > > FD21:root> ip address add 192.168.78.157/24 brd + dev eth0 > > FD21:root> ./route_get > > nlmsg_type = 24 RTM_NEWROUTE > > nlmsg_flags = 0x0 > > readSock() returned 208 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 24 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 254 RT_TABLE_MAIN > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 1 RTN_UNICAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.0 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 3 RTN_BROADCAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.255 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 254 RT_SCOPE_HOST > > rtmsg: rtm_type 2 RTN_LOCAL > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.157 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 3 RTN_BROADCAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.0 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================ > > Destination Gateway Interface Source > > 192.168.78.0 *.*.*.* eth0 192.168.78.157 > > 192.168.78.255 *.*.*.* eth0 192.168.78.157 > > 192.168.78.157 *.*.*.* eth0 192.168.78.157 > > 192.168.78.0 *.*.*.* eth0 192.168.78.157 > > > > route_get displays each route in the response from the kernel > > in detail, followed by the short netstat style summary of the > > routes shown in the 4 above lines. The way I interpret the > > above routes, first to last, is as follows: > > > > 1) The unicast route to the directly connected subnet. > > 2) A broadcast route to the subnet where the broadcast > > address is the all 1s in the host number form. > > 3) The unicast route to the host's own IP address. > > 4) A broadcast route to the subnet where the broadcast > > address is the all 0s in the host number form. > > > > So now I add the alias, an IP address on the same subnet on > > the same device: > > > > FD21:root> ip address add 192.168.78.158/24 brd + dev eth0 > > label eth0:0 > > FD21:root> ip -s -s addr show > > 1: lo: <LOOPBACK> mtu 16436 qdisc noop > > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 > > 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100 > > link/ether 00:60:69:90:02:7a brd ff:ff:ff:ff:ff:ff > > inet 192.168.78.157/24 brd 192.168.78.255 scope global eth0 > > inet 192.168.78.158/24 brd 192.168.78.255 scope global > > secondary eth0:0 > > > > Running route_get, I see one more route has been created: > > > > FD21:root> ./route_get > > nlmsg_type = 24 RTM_NEWROUTE > > nlmsg_flags = 0x0 > > readSock() returned 260 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 24 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 254 RT_TABLE_MAIN > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 1 RTN_UNICAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.0 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 254 RT_SCOPE_HOST > > rtmsg: rtm_type 2 RTN_LOCAL > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.158 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 3 RTN_BROADCAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.255 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 254 RT_SCOPE_HOST > > rtmsg: rtm_type 2 RTN_LOCAL > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.157 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 3 RTN_BROADCAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.0 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================ > > Destination Gateway Interface Source > > 192.168.78.0 *.*.*.* eth0 192.168.78.157 > > 192.168.78.158 *.*.*.* eth0 192.168.78.157 > > 192.168.78.255 *.*.*.* eth0 192.168.78.157 > > 192.168.78.157 *.*.*.* eth0 192.168.78.157 > > 192.168.78.0 *.*.*.* eth0 192.168.78.157 > > > > The new route (the second listed) is the unicast route to the > > additional IP address. All the other routes are the same. > > Near as I can tell so far, all this is correct. > > > > Now I delete the secondary IP address (the alias). So now I > > am back to the single IP address and I would think should be > > in the same state as before I added the alias. > > > > FD21:root> ip address delete 192.168.78.158 dev eth0 label eth0:0 > > FD21:root> ip -s -s addr show > > 1: lo: <LOOPBACK> mtu 16436 qdisc noop > > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 > > 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100 > > link/ether 00:60:69:90:02:7a brd ff:ff:ff:ff:ff:ff > > inet 192.168.78.157/24 brd 192.168.78.255 scope global eth0 > > > > So now I run route_get to see my routes: > > > > FD21:root> ./route_get > > nlmsg_type = 24 RTM_NEWROUTE > > nlmsg_flags = 0x0 > > readSock() returned 156 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 24 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 254 RT_TABLE_MAIN > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 1 RTN_UNICAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.0 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 253 RT_SCOPE_LINK > > rtmsg: rtm_type 3 RTN_BROADCAST > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.255 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================= > > rtmsg: rtm_family 2 AF_INET > > rtmsg: rtm_dst_len 32 > > rtmsg: rtm_src_len 0 > > rtmsg: rtm_tos 0 > > rtmsg: rtm_table 255 RT_TABLE_LOCAL > > rtmsg: rtm_protocol 2 RTPROT_KERNEL > > rtmsg: rtm_scope 254 RT_SCOPE_HOST > > rtmsg: rtm_type 2 RTN_LOCAL > > rtmsg: rtm_flags 0 > > RTA_DST: 192.168.78.157 > > RTA_PREFSRC: 192.168.78.157 > > RTA_OIF: eth0 > > ============================================ > > Destination Gateway Interface Source > > 192.168.78.0 *.*.*.* eth0 192.168.78.157 > > 192.168.78.255 *.*.*.* eth0 192.168.78.157 > > 192.168.78.157 *.*.*.* eth0 192.168.78.157 > > FD21:root> > > > > It seems like I am now missing a route, specifically number > > (4) from the list above: > > > > 4) A broadcast route to the subnet where the broadcast > > address is the all 0s in the host number form. > > > > Is this a feature or a bug (or is this a figment of route_get)? > > If this is a kernel bug, has it been previously reported? > > > > Thanks, > > > > Jeff Haran > > Brocade Communications Systems > > > > p.s. The source to route_get is copied below: > > > > /* 8-04-2005, jharan, > > > > stolen from: > > http://mail.nl.linux.org/kernelnewbies/2003-12/msg00139.html > > > > Hi all, > > i am including another piece of code which i have written to > > print the > > routes > > in the kernel routing table using rtnetlink. Please do let me > > know if there > > is a better way of doing this. > > > > */ > > > > #include <asm/types.h> > > #include <netinet/ether.h> > > #include <netinet/in.h> > > #include <net/if.h> > > #include <stdio.h> > > #include <sys/socket.h> > > #include <sys/ioctl.h> > > #include <linux/netlink.h> > > #include <linux/rtnetlink.h> > > #include <sys/types.h> > > #include <errno.h> > > #include <unistd.h> > > #define _GNU_SOURCE > > #include <getopt.h> > > #include <string.h> > > #include <arpa/inet.h> > > > > #define NL_BUFSIZE 8192 > > > > #ifndef IF_NAMESIZE > > #define IF_NAMESIZE 16 > > #endif > > > > struct route_info{ > > struct route_info *next; > > struct in_addr dstAddr; > > struct in_addr srcAddr; > > struct in_addr gateWay; > > char ifName[IF_NAMESIZE + 50]; > > }; > > > > struct route_info *route_info_head = 0; > > struct route_info *route_info_tail = 0; > > > > typedef struct { > > __u16 nlmsg_type; > > char *name; > > } nlmsg_type_name; > > > > #define NLMSG_NAME_INIT(name) { name, #name } > > > > nlmsg_type_name nlmsg_type_table[] = { > > NLMSG_NAME_INIT(NLMSG_NOOP), > > NLMSG_NAME_INIT(NLMSG_ERROR), > > NLMSG_NAME_INIT(NLMSG_DONE), > > NLMSG_NAME_INIT(NLMSG_OVERRUN), > > NLMSG_NAME_INIT(RTM_NEWLINK), > > NLMSG_NAME_INIT(RTM_DELLINK), > > NLMSG_NAME_INIT(RTM_GETLINK), > > NLMSG_NAME_INIT(RTM_NEWADDR), > > NLMSG_NAME_INIT(RTM_DELADDR), > > NLMSG_NAME_INIT(RTM_GETADDR), > > NLMSG_NAME_INIT(RTM_NEWROUTE), > > NLMSG_NAME_INIT(RTM_DELROUTE), > > NLMSG_NAME_INIT(RTM_GETROUTE), > > NLMSG_NAME_INIT(RTM_NEWNEIGH), > > NLMSG_NAME_INIT(RTM_DELNEIGH), > > NLMSG_NAME_INIT(RTM_GETNEIGH), > > NLMSG_NAME_INIT(RTM_NEWRULE), > > NLMSG_NAME_INIT(RTM_DELRULE), > > NLMSG_NAME_INIT(RTM_GETRULE), > > NLMSG_NAME_INIT(RTM_NEWQDISC), > > NLMSG_NAME_INIT(RTM_DELQDISC), > > NLMSG_NAME_INIT(RTM_GETQDISC), > > NLMSG_NAME_INIT(RTM_NEWTCLASS), > > NLMSG_NAME_INIT(RTM_DELTCLASS), > > NLMSG_NAME_INIT(RTM_GETTCLASS), > > NLMSG_NAME_INIT(RTM_NEWTFILTER), > > NLMSG_NAME_INIT(RTM_DELTFILTER), > > NLMSG_NAME_INIT(RTM_GETTFILTER), > > NLMSG_NAME_INIT(RTM_MAX), > > { 0, 0 } /* end of table marker */ > > }; > > > > char *lookup_nlmsg_type(__u16 nlmsg_type) > > { > > int i; > > > > for (i = 0; nlmsg_type_table[i].name; ++i) { > > if (nlmsg_type_table[i].nlmsg_type == nlmsg_type) > > return nlmsg_type_table[i].name; > > } > > return ("unknown nlmsg_type"); > > } > > > > typedef struct { > > int nlmsg_flag; > > char *name; > > } nlmsg_flags_name; > > > > #define NLMSG_FLAGS_INIT(name) { name, #name } > > > > nlmsg_flags_name nlmsg_flags_table[] = { > > NLMSG_FLAGS_INIT(NLM_F_REQUEST), > > NLMSG_FLAGS_INIT(NLM_F_MULTI), > > NLMSG_FLAGS_INIT(NLM_F_ACK), > > NLMSG_FLAGS_INIT(NLM_F_ECHO), > > NLMSG_FLAGS_INIT(NLM_F_ROOT), > > NLMSG_FLAGS_INIT(NLM_F_MATCH), > > NLMSG_FLAGS_INIT(NLM_F_ATOMIC), > > NLMSG_FLAGS_INIT(NLM_F_REPLACE), > > NLMSG_FLAGS_INIT(NLM_F_EXCL), > > NLMSG_FLAGS_INIT(NLM_F_CREATE), > > NLMSG_FLAGS_INIT(NLM_F_APPEND), > > { 0, 0 } /* end of table marker */ > > }; > > > > __u16 print_nlmsg_flags(__u16 nlmsg_flags) > > { > > int i; > > > > /* while some flag bits are still set */ > > while (nlmsg_flags) { > > /* search table for a flag where we know what it is */ > > for (i = 0; nlmsg_flags_table[i].name; ++i) { > > /* known flag? */ > > if (nlmsg_flags_table[i].nlmsg_flag & > > nlmsg_flags) { > > /* print its name */ > > fprintf(stdout, "%s ", > > nlmsg_flags_table[i].name); > > /* reset the flag */ > > nlmsg_flags &= > > ~nlmsg_flags_table[i].nlmsg_flag; > > break; > > } > > } > > /* if we couldn't find any matching flags, bail */ > > if (!nlmsg_flags_table[i].name) > > break; > > } > > /* if any unknown flags left, display them numerically */ > > if (nlmsg_flags) > > fprintf(stdout, "mystery flags 0x%x", nlmsg_flags); > > return nlmsg_flags; > > } > > > > typedef struct { > > int rtmsg_flag; > > char *name; > > } rtmsg_flags_name; > > > > #define RTMSG_FLAGS_INIT(name) { name, #name } > > > > rtmsg_flags_name rtmsg_flags_table[] = { > > RTMSG_FLAGS_INIT(RTM_F_NOTIFY), > > RTMSG_FLAGS_INIT(RTM_F_CLONED), > > RTMSG_FLAGS_INIT(RTM_F_EQUALIZE), > > { 0, 0 } /* end of table marker */ > > }; > > > > unsigned int print_rtmsg_flags(unsigned int rtmsg_flags) > > { > > int i; > > > > /* while some flag bits are still set */ > > while (rtmsg_flags) { > > /* search table for a flag where we know what it is */ > > for (i = 0; rtmsg_flags_table[i].name; ++i) { > > /* known flag? */ > > if (rtmsg_flags_table[i].rtmsg_flag & > > rtmsg_flags) { > > /* print its name */ > > fprintf(stdout, "%s ", > > rtmsg_flags_table[i].name); > > /* reset the flag */ > > rtmsg_flags &= > > ~rtmsg_flags_table[i].rtmsg_flag; > > break; > > } > > } > > /* if we couldn't find any matching flags, bail */ > > if (!rtmsg_flags_table[i].name) > > break; > > } > > /* if any unknown flags left, display them numerically */ > > if (rtmsg_flags) > > fprintf(stdout, "mystery flags 0x%x", rtmsg_flags); > > return rtmsg_flags; > > } > > > > int readSock(int sockFd, char *bufPtr, int seqNum, int pId) > > { > > struct nlmsghdr *nlHdr; > > int readLen = 0, flag = 0, msgLen = 0; > > > > do{ > > /* Recieve response from kernel */ > > if ((readLen = recv(sockFd, bufPtr, NL_BUFSIZE > > - msgLen, 0)) < 0){ > > perror("SOCK READ: "); > > return -1; > > } > > nlHdr = (struct nlmsghdr *)bufPtr; > > > > fprintf(stdout, "nlmsg_type = %d %s\n", > > nlHdr->nlmsg_type, > > lookup_nlmsg_type(nlHdr->nlmsg_type)); > > fprintf(stdout, "nlmsg_flags = 0x%x ", > > nlHdr->nlmsg_flags); > > print_nlmsg_flags(nlHdr->nlmsg_flags); > > fprintf(stdout, "\n"); > > > > /* Check if header is valid */ > > if (NLMSG_OK(nlHdr, readLen) == 0) { > > fprintf(stdout, "NLMSG_OK == 0\n"); > > return -1; > > } > > > > /* check for error packet */ > > if (nlHdr->nlmsg_type == NLMSG_ERROR) { > > struct nlmsgerr *errHdr; > > > > errHdr = (struct nlmsgerr *) NLMSG_DATA(nlHdr); > > fprintf(stdout, > > "Received NLMSG_ERROR, error = %d %s\n", > > errHdr->error, > > strerror(-(errHdr->error))); > > return -1; > > } > > > > /* Check if its the last message */ > > if (nlHdr->nlmsg_type == NLMSG_DONE) { > > flag = 1; > > break; > > } else { > > /* Move the buffer pointer appropriately */ > > bufPtr += readLen; > > msgLen += readLen; > > } > > #if 1 > > /* jharan, though it seems to work, not clear to me > > that the following > > is "correct". I think we should only be looking > > for the NLMSG_DONE > > to terminate, like is done above */ > > if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0){ > > flag = 1; > > break; > > } > > #endif > > } while ((nlHdr->nlmsg_seq != seqNum) || > > (nlHdr->nlmsg_pid != pId) || (flag == 0)); > > return msgLen; > > } > > > > /* For printing the routes. */ > > void printRoute(struct route_info *rtInfo) > > { > > char tempBuf[512]; > > > > /* Print Destination address */ > > if(rtInfo->dstAddr.s_addr != 0) > > strcpy(tempBuf, (char *)inet_ntoa((struct > > in_addr) (rtInfo->dstAddr))); > > else > > sprintf(tempBuf,"*.*.*.*\t"); > > fprintf(stdout,"%s\t", tempBuf); > > > > /* Print Gateway address */ > > if(rtInfo->gateWay.s_addr != 0) > > strcpy(tempBuf, (char *)inet_ntoa((struct > > in_addr) (rtInfo->gateWay))); > > else > > sprintf(tempBuf,"*.*.*.*\t"); > > fprintf(stdout,"%s\t", tempBuf); > > > > /* Print Interface Name*/ > > fprintf(stdout,"%s\t\t", rtInfo->ifName); > > > > /* Print Source address */ > > if(rtInfo->srcAddr.s_addr != 0) > > strcpy(tempBuf, (char *)inet_ntoa((struct > > in_addr) (rtInfo->srcAddr))); > > else > > sprintf(tempBuf,"*.*.*.*\t"); > > fprintf(stdout,"%s\n", tempBuf); > > } > > > > /* For parsing the route info returned */ > > void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) > > { > > struct rtmsg *rtMsg; > > struct rtattr *rtAttr; > > int rtLen; > > char tempBuf[100]; > > > > rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr); > > > > fprintf(stdout, > > "=============================================\n"); > > fprintf(stdout, "rtmsg: rtm_family %d\t", rtMsg->rtm_family); > > if (rtMsg->rtm_family == AF_INET) > > fprintf(stdout, "AF_INET\n"); > > else > > fprintf(stdout, "mystery\n"); > > > > /* from the data, rtm_dst_len appears the be the number of bits > > set in the subnet mask, e.g. the 8 in 10.0.0.1/8. > > in case of rtm_dst_len == 32, looks like a > > host route */ > > fprintf(stdout, "rtmsg: rtm_dst_len %d\n", rtMsg->rtm_dst_len); > > /* rtm_src_len always seems to be 0, not sure what it means */ > > fprintf(stdout, "rtmsg: rtm_src_len %d\n", rtMsg->rtm_src_len); > > fprintf(stdout, "rtmsg: rtm_tos %d\n", rtMsg->rtm_tos); > > fprintf(stdout, "rtmsg: rtm_table %d\t", rtMsg->rtm_table); > > > > if (rtMsg->rtm_table == RT_TABLE_UNSPEC) > > fprintf(stdout, "RT_TABLE_UNSPEC\n"); > > else if (rtMsg->rtm_table == RT_TABLE_DEFAULT) > > fprintf(stdout, "RT_TABLE_DEFAULT\n"); > > else if (rtMsg->rtm_table == RT_TABLE_MAIN) > > fprintf(stdout, "RT_TABLE_MAIN\n"); > > else if (rtMsg->rtm_table == RT_TABLE_LOCAL) > > fprintf(stdout, "RT_TABLE_LOCAL\n"); > > else > > fprintf(stdout, "mystery\n"); > > > > fprintf(stdout, "rtmsg: rtm_protocol %d\t", > > rtMsg->rtm_protocol); > > > > if (rtMsg->rtm_protocol == RTPROT_REDIRECT) > > fprintf(stdout, "RTPROT_REDIRECT\n"); > > else if (rtMsg->rtm_protocol == RTPROT_KERNEL) > > fprintf(stdout, "RTPROT_KERNEL\n"); > > else if (rtMsg->rtm_protocol == RTPROT_BOOT) > > fprintf(stdout, "RTPROT_BOOT\n"); > > else if (rtMsg->rtm_protocol == RTPROT_STATIC) > > fprintf(stdout, "RTPROT_STATIC\n"); > > else > > /* there's more of these in rtnetlink.h, > > just handling the common ones for now */ > > fprintf(stdout, "mystery\n"); > > > > fprintf(stdout, "rtmsg: rtm_scope %d\t", rtMsg->rtm_scope); > > > > if (rtMsg->rtm_scope == RT_SCOPE_UNIVERSE) > > fprintf(stdout, "RT_SCOPE_UNIVERSE\n"); > > else if (rtMsg->rtm_scope == RT_SCOPE_SITE) > > fprintf(stdout, "RT_SCOPE_SITE\n"); > > else if (rtMsg->rtm_scope == RT_SCOPE_LINK) > > fprintf(stdout, "RT_SCOPE_LINK\n"); > > else if (rtMsg->rtm_scope == RT_SCOPE_HOST) > > fprintf(stdout, "RT_SCOPE_HOST\n"); > > else if (rtMsg->rtm_scope == RT_SCOPE_NOWHERE) > > fprintf(stdout, "RT_SCOPE_NOWHERE\n"); > > else > > fprintf(stdout, "mystery\n"); > > > > fprintf(stdout, "rtmsg: rtm_type %d\t", rtMsg->rtm_type); > > > > if (rtMsg->rtm_type == RTN_UNSPEC) > > fprintf(stdout, "RTN_UNSPEC\n"); > > else if (rtMsg->rtm_type == RTN_UNICAST) > > fprintf(stdout, "RTN_UNICAST\n"); > > else if (rtMsg->rtm_type == RTN_LOCAL) > > fprintf(stdout, "RTN_LOCAL\n"); > > else if (rtMsg->rtm_type == RTN_BROADCAST) > > fprintf(stdout, "RTN_BROADCAST\n"); > > else if (rtMsg->rtm_type == RTN_ANYCAST) > > fprintf(stdout, "RTN_ANYCAST\n"); > > else if (rtMsg->rtm_type == RTN_MULTICAST) > > fprintf(stdout, "RTN_MULTICAST\n"); > > else if (rtMsg->rtm_type == RTN_BLACKHOLE) > > fprintf(stdout, "RTN_BLACKHOLE\n"); > > else if (rtMsg->rtm_type == RTN_UNREACHABLE) > > fprintf(stdout, "RTN_UNREACHABLE\n"); > > else if (rtMsg->rtm_type == RTN_PROHIBIT) > > fprintf(stdout, "RTN_PROHIBIT\n"); > > else if (rtMsg->rtm_type == RTN_THROW) > > fprintf(stdout, "RTN_THROW\n"); > > else if (rtMsg->rtm_type == RTN_NAT) > > fprintf(stdout, "RTN_NAT\n"); > > else if (rtMsg->rtm_type == RTN_XRESOLVE) > > fprintf(stdout, "RTN_XRESOLVE\n"); > > else > > fprintf(stdout, "mystery\n"); > > > > fprintf(stdout, "rtmsg: rtm_flags %d ", rtMsg->rtm_flags); > > print_rtmsg_flags(rtMsg->rtm_flags); > > fprintf(stdout, "\n"); > > > > #if 0 > > /* If the route is not for AF_INET or does not belong > > to main routing table > > then return. */ > > if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table > > != RT_TABLE_MAIN)) > > return; > > #endif > > > > /* get the rtattr field */ > > rtAttr = (struct rtattr *)RTM_RTA(rtMsg); > > rtLen = RTM_PAYLOAD(nlHdr); > > for(;RTA_OK(rtAttr,rtLen);rtAttr = RTA_NEXT(rtAttr,rtLen)){ > > switch(rtAttr->rta_type) { > > case RTA_DST: > > inet_ntop(AF_INET, RTA_DATA(rtAttr), > > tempBuf, sizeof(tempBuf)); > > fprintf(stdout, "RTA_DST: %s\n",tempBuf); > > rtInfo->dstAddr.s_addr= *(u_int > > *)RTA_DATA(rtAttr); > > break; > > case RTA_SRC: > > inet_ntop(AF_INET, RTA_DATA(rtAttr), > > tempBuf, sizeof(tempBuf)); > > fprintf(stdout, "RTA_SRC: %s\n",tempBuf); > > break; > > case RTA_IIF: > > if (!if_indextoname(*(int > > *)RTA_DATA(rtAttr), tempBuf)) > > sprintf(tempBuf, "errno %d", errno); > > fprintf(stdout, "RTA_IIF: %s\n", tempBuf); > > break; > > case RTA_OIF: > > if (!if_indextoname(*(int > > *)RTA_DATA(rtAttr), tempBuf)) > > sprintf(tempBuf, "errno %d", errno); > > fprintf(stdout, "RTA_OIF: %s\n", tempBuf); > > strcpy(rtInfo->ifName, tempBuf); > > break; > > case RTA_GATEWAY: > > inet_ntop(AF_INET, RTA_DATA(rtAttr), > > tempBuf, sizeof(tempBuf)); > > fprintf(stdout, "RTA_GATEWAY: %s\n",tempBuf); > > rtInfo->gateWay.s_addr = *(u_int > > *)RTA_DATA(rtAttr); > > break; > > case RTA_PREFSRC: > > inet_ntop(AF_INET, RTA_DATA(rtAttr), > > tempBuf, sizeof(tempBuf)); > > fprintf(stdout, "RTA_PREFSRC: %s\n",tempBuf); > > rtInfo->srcAddr.s_addr = *(u_int > > *)RTA_DATA(rtAttr); > > break; > > default: > > /* there's more RTA_s under > > rtattr_type_t in rtnetlink.h, > > just covering some common ones above */ > > fprintf(stdout, "RTA mystery: %d len %d\n", > > rtAttr->rta_type, rtAttr->rta_len); > > break; > > } > > } > > return; > > } > > > > unsigned char command_rtm_table; > > unsigned char command_rtm_protocol; > > unsigned char command_rtm_family; > > int command_ack; > > int command_any_args; > > > > struct option long_options[] = { > > { "table", required_argument, 0, 't'}, > > { "protocol", required_argument, 0, 'p'}, > > { "family", required_argument, 0, 'f' }, > > { "ack", no_argument, 0, 'a'}, > > { 0, 0, 0, 0} > > }; > > > > char short_options[] = "t:p:f:a"; > > > > int parse_command_line(int argc, char *argv[]) > > { > > int rc; > > int option_index; > > unsigned int x; > > > > while (1) > > { > > rc = getopt_long(argc, argv, short_options, > > long_options, &option_index); > > switch (rc) { > > case 't' : > > sscanf(optarg, "%u", &x); > > command_rtm_table = (unsigned char) x; > > printf("command_rtm_table = > > %u\n", command_rtm_table); > > command_any_args++; > > break; > > case 'p' : > > sscanf(optarg, "%u", &x); > > command_rtm_protocol = > > (unsigned char) x; > > printf("command_rtm_protcol = > > %u\n", command_rtm_protocol); > > command_any_args++; > > break; > > case 'f' : > > sscanf(optarg, "%u", &x); > > command_rtm_family = (unsigned char) x; > > printf("command_rtm_family = > > %u\n", command_rtm_family); > > command_any_args++; > > break; > > case 'a' : > > command_ack = 1; > > printf("acknowledgement enabled\n"); > > break; > > case -1 : > > break; > > default : > > printf("unrecognized option %c > > (%d)\n", rc, rc); > > break; > > } > > > > if (rc == -1) > > break; > > } > > > > return 0; > > } > > > > int main(int argc, char *argv[]) > > { > > int sock, len, msgSeq = 0; > > struct nlmsghdr *nlMsg; > > struct rtmsg *rtMsg; > > struct route_info *rtInfo; > > char msgBuf[NL_BUFSIZE]; > > > > if (parse_command_line(argc, argv)) > > return -1; > > > > /* Create Socket */ > > if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) > > perror("Socket Creation: "); > > > > /* Initialize the buffer */ > > memset(msgBuf, 0, NL_BUFSIZE); > > > > /* point the header and the msg structure pointers into > > the buffer */ > > nlMsg = (struct nlmsghdr *)msgBuf; > > rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg); > > > > rtMsg->rtm_table = command_rtm_table; > > rtMsg->rtm_protocol = command_rtm_protocol; > > rtMsg->rtm_family = command_rtm_family; > > > > /* Fill in the nlmsg header*/ > > // Length of message. > > nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); > > // Get the routes from kernel routing table . > > nlMsg->nlmsg_type = RTM_GETROUTE; > > > > > > nlMsg->nlmsg_flags = NLM_F_REQUEST; > > #if 0 > > /* it appears that only NLM_F_REQUEST | NLM_F_ROOT is supported > > by the RTM_GETROUTE service. when I attempt to setup the > > fields of ifinfomsg sent to the kernel as > > above, I either > > get all routes back when NLM_F_ROOT is specified or an > > error message when its not, jharan, 8-08-2005 */ > > if (!command_any_args) > > #endif > > nlMsg->nlmsg_flags |= NLM_F_ROOT; > > > > /* it appears the NLM_F_ACK has no effect on gets. guess this > > makes sense given that the get response is sufficent > > acknowledgement, jharan, 8-08-2005 */ > > if (command_ack) > > nlMsg->nlmsg_flags |= NLM_F_ACK; > > > > // Sequence of the message packet. > > nlMsg->nlmsg_seq = msgSeq++; > > // PID of process sending the request. > > nlMsg->nlmsg_pid = getpid(); > > > > /* Send the request */ > > if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0){ > > printf("Write To Socket Failed...\n"); > > return -1; > > } > > > > /* Read the response */ > > if((len = readSock(sock, msgBuf, msgSeq, getpid())) < > > 0) { > > printf("Read From Socket Failed...\n"); > > return -1; > > } > > > > printf("readSock() returned %d\n", len); > > > > /* Parse and print the response */ > > for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){ > > rtInfo = (struct route_info *) > > malloc(sizeof(struct route_info)); > > if (!rtInfo) { > > fprintf(stdout, "malloc() failed\n"); > > return -1; > > } > > memset(rtInfo, 0, sizeof(struct route_info)); > > parseRoutes(nlMsg, rtInfo); > > if (!route_info_head) { > > route_info_head = rtInfo; > > route_info_tail = rtInfo; > > } else { > > route_info_tail->next = rtInfo; > > route_info_tail = rtInfo; > > } > > } > > close(sock); > > /* netstat style display of accumulated data */ > > fprintf(stdout, > > "============================================\n"); > > fprintf(stdout, "Destination\tGateway\t\tInterface\tSource\n"); > > for (rtInfo = route_info_head; rtInfo; rtInfo = rtInfo->next) > > printRoute(rtInfo); > > return 0; > > } > > > > > > - > > : send the line "unsubscribe > > linux-net" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html > > > > > - > : send the line "unsubscribe linux-net" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- ~Randy - : send the line "unsubscribe linux-net" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html