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? 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