#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
#define NIP6(addr) \
ntohs((addr).s6_addr16[0]), \
ntohs((addr).s6_addr16[1]), \
ntohs((addr).s6_addr16[2]), \
ntohs((addr).s6_addr16[3]), \
ntohs((addr).s6_addr16[4]), \
ntohs((addr).s6_addr16[5]), \
ntohs((addr).s6_addr16[6]), \
ntohs((addr).s6_addr16[7])
#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
#define INFINITY_LIFE_TIME 0xFFFFFFFFU
main()
{
struct {
struct nlmsghdr n;
struct ifaddrmsg r;
// char buf[1024];
} req;
struct rtattr *rta;
struct sockaddr_in6 *sin6p;
struct sockaddr_in *sinp;
int status;
char buf[16384];
struct nlmsghdr *nlmp;
struct ifaddrmsg *rtmp;
struct rtattr *rtatp;
int rtattrlen;
struct in_addr *inp;
struct in6_addr *in6p;
struct ifa_cacheinfo *cache_info;
int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
/* We use RTM_GETADDR to fetch the ip address from the kernel interface table *
* So what we do here is pretty simple, we populate the msg structure (req) *
* the size of the message buffer is specified to netlink message header, and *
* flags values are set as NLM_F_ROOT | NLM_F_REQUEST. The request flag must *
* be set for all messages requesting the data from kernel. The root flag is *
* used to notify the kernel to return the full tabel. Another flag (not used)*
* is NLM_F_MATCH. This is used to get only speficed entried in the table. *
* At the time of writing this program this flag is not implemented in kernel */
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
req.n.nlmsg_type = RTM_GETADDR;
/* AF_INET6 is used to signify the kernel to fetch only ipv6 entires. *
* Replacing this with AF_INET will fetch ipv4 address table. */
req.r.ifa_family = AF_INET6;
/* Fill up all the attributes for the rtnetlink header. The code is pretty easy*
* to understand. The lenght is very important. We use 16 to signify the ipv6 *
* address. If the user chooses to use AF_INET (ipv4) the length has to be *
* RTA_LENGTH(4) */
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
rta->rta_len = RTA_LENGTH(16);
/* Time to send and recv the message from kernel */
status = send(fd, &req, req.n.nlmsg_len, 0);
if (status < 0) {
perror("send");
return 1;
}
status = recv(fd, buf, sizeof(buf), 0);
if (status < 0) {
perror("recv");
return 1;
}
if(status == 0){
printf("EOF\n");
return 1;
}
/* Typically the message is stored in buf, so we need to parse the message to *
* get the required data for our display. */
for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);){
int len = nlmp->nlmsg_len;
int req_len = len - sizeof(*nlmp);
if (req_len<0 || len>status) {
printf("error\n");
return -1;
}
if (!NLMSG_OK(nlmp, status)) {
printf("NLMSG not OK\n");
return 1;
}
rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp);
rtatp = (struct rtattr *)IFA_RTA(rtmp);
/* Start displaying the index of the interface */
printf("Index Of Iface= %d\n",rtmp->ifa_index);
rtattrlen = IFA_PAYLOAD(nlmp);
for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {
/* Here we hit the fist chunk of the message. Time to validate the *
* the type. For more info on the different types see man(7) rtnetlink*
* The table below is taken from man pages. *
* Attributes *
* rta_type value type description *
* ------------------------------------------------------------- *
* IFA_UNSPEC - unspecified. *
* IFA_ADDRESS raw protocol address interface address *
* IFA_LOCAL raw protocol address local address *
* IFA_LABEL asciiz string name of the interface *
* IFA_BROADCAST raw protocol address broadcast address. *
* IFA_ANYCAST raw protocol address anycast address *
* IFA_CACHEINFO struct ifa_cacheinfo Address information. */
if(rtatp->rta_type == IFA_CACHEINFO){
cache_info = (struct ifa_cacheinfo *)RTA_DATA(rtatp);
if (cache_info->ifa_valid == INFINITY_LIFE_TIME)
printf("valid_lft forever\n");
else
printf("valid_lft %usec\n", cache_info->ifa_valid);
if (cache_info->ifa_prefered == INFINITY_LIFE_TIME)
printf(" preferred_lft forever\n");
else
printf(" preferred_lft %usec\n",cache_info->ifa_prefered);
}
/* NOTE: All the commented code below can be used as it is for ipv4 table */
if(rtatp->rta_type == IFA_ADDRESS){
// inp = (struct in_addr *)RTA_DATA(rtatp);
in6p = (struct in6_addr *)RTA_DATA(rtatp);
printf("addr0: " NIP6_FMT "\n",NIP6(*in6p));
// printf("addr0: "NIPQUAD_FMT"\n",NIPQUAD(*inp));
}
if(rtatp->rta_type == IFA_LOCAL){
// inp = (struct in_addr *)RTA_DATA(rtatp);
in6p = (struct in6_addr *)RTA_DATA(rtatp);
printf("addr1: " NIP6_FMT "\n",NIP6(*in6p));
// printf("addr1: "NIPQUAD_FMT"\n",NIPQUAD(*inp));
}
if(rtatp->rta_type == IFA_BROADCAST){
// inp = (struct in_addr *)RTA_DATA(rtatp);
in6p = (struct in6_addr *)RTA_DATA(rtatp);
printf("bcataddr: " NIP6_FMT "\n",NIP6(*in6p));
// printf("Bcast addr: "NIPQUAD_FMT"\n",NIPQUAD(*inp));
}
if(rtatp->rta_type == IFA_ANYCAST){
//inp = (struct in_addr *)RTA_DATA(rtatp);
in6p = (struct in6_addr *)RTA_DATA(rtatp);
printf("anycastaddr: "NIP6_FMT"\n",NIP6(*in6p));
// printf("anycast addr: "NIPQUAD_FMT"\n",NIPQUAD(*inp));
}
}
status -= NLMSG_ALIGN(len);
nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
}
}
Wednesday, January 28, 2009
Sample Code To Learn Netlink Infrastructure
Wednesday, December 10, 2008
Collecting trace data from Linux kernel using klog
I came across the klog kernel patch very recently. It was written by Tom Zanussi in 2005. Recently, Vaidyanathan Srinivasan made a few changes to klog, by adding the function ktrace, which makes it even more simpler to use it. Below, I describe how one could make use of this mechanism. Before we begin, note that klog is a static tracer. So, everytime you want to trace new code, the kernel will need to be recompiled.
Apply the klog patch to your kernel. This includes the changes made by Vaidy for ktrace. To trace through any code (ie, kernel routine), ktrace provides the following infrastructure:
1) Trace events (defined in include/linux/ktrace.h):
enum KTRACE_EVENT_ID {
KT_EVENT_FUNC_ENTER,
KT_EVENT_FUNC_EXIT,
KT_EVENT_INFO1,
KT_EVENT_INFO2,
KT_EVENT_INFO3,
KT_EVENT_INFO4,
KT_EVENT_ERROR,
};
2) Enumerator for the functions to be traced (include/linux/ktrace.h):
enum KTRACE_FUNC_ID {
KT_FUNC_tick_nohz_stop_sched_tick, /* 0 */
KT_FUNC_tick_nohz_restart_sched_tick, /* 1 */
};
3) Logging routines (lib/ktrace.c):
void ktrace_log2(unsigned char func, unsigned char event, uint64_t u1, uint64_t u2);
void ktrace_log4(unsigned char func, unsigned char event, uint32_t u1, uint32_t u2,
uint32_t u3, uint32_t u4);
So now, if you want to capture timestamps between the entry and exit of a routine x (assuming the routine executes in preempt disable mode), the following changes would be needed:
a) Add that function into the KTRACE_FUNC_ID,
enum KTRACE_FUNC_ID {
KT_FUNC_tick_nohz_stop_sched_tick, /* 0 */
KT_FUNC_tick_nohz_restart_sched_tick, /* 1 */
+ KT_FUNC_my_func_to_trace,
};
b) At the entry of the routine, capture the timestamp:
ktime_to_ns(start);
At the exit of the routine, make a call to ktrace_log2,
ktrace_log2(KT_FUNC_my_func_to_trace, KT_FUNC_EXIT,ktime_to_ns(now)-start, 0);
Now, whenever the routine is executed, the ktrace_log2 call will dump the information into the klog buffer. Compile and reboot into the modified kernel. Mount debugfs:
# mkdir /debug
# mount -t debugfs nodev /debug
Now run the klog.c program
# ./klog [-b subbuf-size -n n_subbufs]
The resultant trace data will be stored in ./cpu0..cpu[x] files. Remember that this data is in binary format and needs to be processed to convert into ascii. For that, a simple python program can be used. A sample python script could be as follows: (adopted from this script)
import os
import sys
import struct
# Globals
nr_cpus = 4
tracedata = []
cookedtrace = open("trace.txt", 'w')
for cpu in range(nr_cpus):
tracefile = open("cpu%d" % cpu)
while(1):
tracerecord = tracefile.read(24)
if not len(tracerecord):
break
tracerecordfields = struct.unpack("IBBBxQQ", tracerecord)
tracedata.append(tracerecordfields)
cookedtrace.write("U%-10d C%d F%X E%x %10d %10d\n" % tracerecordfields)
cookedtrace.close()
The above will generate trace.txt file, with the data in the different columsn. Further processing could be done based on the particular event type and function id, to capture more information. From the information captured, one could easily plot graphs usig gnuplot.
Friday, November 28, 2008
Understanding PER_CPU_LOCKED
The implication of this new macro is a performance hit, as the per-cpu variable being read on one processor could well be for some other processor.
This performance hit is alright as in "realtime" we care more about "latency" and "determinism" than "overall system performance".
Wednesday, November 26, 2008
Installing Amarok 2 Beta/RC on Fedora 9

First you need to install cmake
# yum install cmake
After that, try compiling with
# cmake -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix` -DCMAKE_BUILD_TYPE=debugfull
On a typical Fedora 9 setup, you'd instantly hit errors. Thats because multiple devel packages are missing.
# yum install -y kdelibs phonon* libgpod-devel prce
Another package that needs to be installed is libtags. Installing it via yum didnot solve the problem for me. So I had to download the code and install it from here
You will need libmtp. But the ones available in Fedora 9 won't help. Take ones from Fedora 10 repo from here and here
During make i hit a problem, amarok couldn't file libprce and libprceposix, even though they were installed.
# ln -s /usr/lib/libpcreposix.so.0 /usr/lib/libpcreposix
# ln -s /lib/libpcre.so.0 /usr/lib/libpcre.so
Phew!
After all of this, trying compiling amarok again.This time everything should go smooth.
Then do a make and make install.
The make step takes a lot of time.
You should be all set to use the latest and greatest Music Player i.e Amarok 2 RC1 (pun intended!)
The easy way to do this just install the rpm. Grab the beta rpm from here
# yum localinstall amarok-1.90-1.fc9.i386.rpm
The above will resolve all the necessary dependencies and install amarok 2 beta 1
Powered by ScribeFire.
Sunday, November 16, 2008
Custom Search in Firefox
How does one go about adding a custom search to a site without inherent search capabilities like eg. lkml.org ?
Assuming you are in your home directory.
[cheezo@phaedrus ~]$ pwd
/home/cheezo
[cheezo@phaedrus ~]$ cd `find .mozilla/ -name 'searchplugins' `
[cheezo@phaedrus searchplugins]$ ls
goosh.xml imdb.xml linkedin.xml lkml.xml
Here there are already some xml files for those custom search engines.
lkml.xml is the file of our interest, lets have a look
[cheezo@phaedrus searchplugins]$ cat lkml.xml
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Google</ShortName>
<Description>Google Search
<InputEncoding>UTF-8
<Url type="application/x-suggestions+json" method="GET" template="http://www.google.com/custom?sitesearch=lkml.org&;client=firefox&hl={moz:locale}&q={searchTerms}"/>
<Url type="text/html" method="GET" template="http://www.google.com/search">
<Param name="q" value="{searchTerms}"/>
<Param name="ie" value="utf-8"/>
<Param name="oe" value="utf-8"/>
<Param name="aq" value="t"/>
<Param name="rls" value="{moz:distributionID}:{moz:locale}:{moz:official}"/>
<MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
</Url>
<SearchForm>http://www.google.com/firefox
</SearchPlugin>
On the 5th line, we have template="http://www.google.com/custom?sitesearch=site_name". Here site_name = lkml.org. Incase you want to search any other site, replace site_name with that site.
Other terms are self-explanatory.
To ensure a new search engine option shows in Firefox; Firefox needs to be rebooted.
Note:This is my first post which experiments with Cascading Style Sheets (CSS).
Powered by ScribeFire.
Saturday, November 15, 2008
Finding out processor topology
physical id: physical package id of the CPU
siblings: number of processors, present in the same physical package. This counts both hardware threads and cores
core id: Core id of the processor
cpu cores: number of cores in the physical package
Also, the flags field contains a flag called "ht", to indicate if hardware multi-threading is supported by the processor
So, if for a physical package, the number of siblings is equal to the number of cores and both are greater than 2, it would mean that it has multiple cores and does not support hardware threads. If the number of siblings is greater than 2 but the number of cores is one, then that would imply that there is only a single core in one package and that there is support for hardware threads. Some systems could have processors that are both, multi-threaded and ulti-core. For these, the number of siblings and the number of cores in a physical package would be more than one.
The topology information can be very useful. It can be used to bind certain application or kernel threads, and/or irqs to particular cpus, to improve throughput by reducing resource contention and aid the scheduler in making better load balancing decisions.
Tuesday, November 4, 2008
Funny Pull Request @ netdev
From: "John W. Linville"
Date: Fri, 31 Oct 2008 19:37:35 -0400
> Here is a spooky Halloween pull request for wireless bits intended for
> 2.6.29 -- Boo! Are you scared?
Best pull request ever :-)
> There is a ton of stuff here. The good news is that it has been cooking
> in wireless-testing for a while and it seems OK. :-) There are some
> warning in the build like "‘__IEEE80211_CONF_SHORT_SLOT_TIME’ is
> deprecated". Don't worry, I already have more patches cooking in
> wireless-testing that will take care of those warnings in the next
> round.
>
> Please let me know if there are problems!
Pulled, thanks a lot!