RE: kernel bug? - routing table entry lost

From: Randy.Dunlap
Date: Wed Sep 14 2005 - 13:44:27 EST


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;
> > }
> >
> >
> > -
> > To unsubscribe from this list: 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
> >
> >
> -
> To unsubscribe from this list: 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
-
To unsubscribe from this list: 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