Tuesday, April 26, 2005

Dreams

A few days back, while chatting with a friend I said something which got me thinking. Did I hear it somewhere or did it just come out of my conscious ? I dont know, but here it is.

"In life, always follow your dreams. Just dont put all your hopes on them. Because if they dont come true, you will atleast be saved from falling flat on your face."

Have I become very pessemistic in life ?? Or is it just the truth ?? I dont know for sure. But the more I think about it, I really do feel that is the truth.

But what are dreams ? I feel they are milestones that we choose to keep in our life, work for it and then at the end of the day hope that they will come true. Some do come true and then we believe in all the good there is in this world. And some dont and then we or atleast I, believe that this world is a cruel place :) (well not quite)

But all said and done, dreams are what make your life worth living. When you are going through a bad phase of life, dreams for better times is what gets you through the day. Life is short, dream big then you will live big. I should really do that. I have spent a lot of time clinging on to my past, afraid to let it go. I think its time for me to dream a lil and live life as its meant to be.

Tuesday, April 12, 2005

CVS encounter

Finally started using CVS for my project. Maybe it wont grow as large as I expect, but hey I got to learn a new thing and thats what counts =). So here is a lil tutorial of what I did, so that I can refer later on.

I refered to the following links

1. http://cvsbook.red-bean.com/cvsbook.html#Starting%20A%20Repository
2. http://www.sys-con.com/linux/article.cfm?id=40

What is CVS ? CVS stands for Concurrent Version Control and is used for collaboration and version control.

Most linux distributions (nowdays) come with CVS pre-installed. So all I had to do was start using it. Here is a step by step guide of what I did

1. First one needs a directory where CVS will store the information about the projects that are being version controlled. This is called as a 'repository'. So in short we need to create a repository. The following command was used for it

cvs -d /home/CVSRoot init

So '/home/CVSRoot' is the repository.
I did the following because I was not able to access cvs remotely. So I created a new group called cvs at the server and populated the member list for it. Then I went in /home/CVSRoot and ran the following 2 commands

chgrp -R cvs .
chmod ug+rwx . CVSROOT

2. To make life simpler(lazy me), we can set some environment variables so that the system knows about this repository. I changed the /etc/profile file for this. First make a backup copy in case things go wrong. Then add these two lines in it

export CVSROOT='/home/CVSRoot'
export CVSEDITOR=/bin/vi

So now when I try to add files to my repository, I dont need to specify the CVSROOT explicitly i.e. I dont have to give the complete path name of the repository everytime.

3. Now I was ready to add my project files into it. First go to the directory which contains the files and/or direcotries that you want to add to the repository. I went to /home/rbj2/split_programs. This directory contains all my project files for which I want a version control. Once here, I ran the following command

cvs import split_programs split_tcp start

where split_programs: is the project name by which CVS will create an entry
split_tcp: is a vendor tag. I have o clue what this is :-D

After executing, vi editor gets executed. CVS forces you to write a comment. SO just wrote a random comment. Well it wasnt that random. Anyways, you can supress this by using the -m option. Well, after this command I could see an entry for my project under /home/CVSRoot/.

4. Now I wanted to create remote access so I could store my changes directly from frudo and not have to ftp everytime to turing. So, I start by checking in /etc/services file whether it contains the following line

cvspserver 2401/tcp

It was there. So cool, else I would need to add it in there.
Now go to /etc/xinetd.d. Create a new file called 'cvs'. One can give any name but I choose cvs. And then wrote the following there

#default: on
#description: adding CVS stream for remote CVS access

service cvspserver
{
socket_type=stream
protocol=tcp
wait=no
user=root
disable=no
server=/usr/bin/cvs
server_args= -f --allow-root=/home/CVSRoot pserver
}

Now run the following command

/etc/rc.d/init.d/xinet restart

This will restart xinetd, so our changes will come in effect.

5. But I wanted secure access, so I decided upon having a password authenticated setup. I create a new file 'passwd' in /home/CVSRoot/CVSROOT/. And copy my login info from /etc/shadow. Keep the first two fields and omit everything else. Save and we are ready to go.

6. At frudo, I first create the CVSROOT env variable as

CVSROOT=:pserver:rbj2@turing.internet.lab:/home/CVSRoot

and then to connect I use 'cvs login'
It asks me for my password and boom, I am in.

If I want to checkout the files at frudo, I do 'cvs checkout split_programs'.

Saturday, April 09, 2005

Problems faced till now

Here is a list of problems that I have faced while writing code for my thesis. Not a complete, but all that I can remember at the moment. Hopefully this will help me later (and it should)

1. Since I am working at PRE_ROUTING hook, I can read all the fields of iphdr. However the tcphdr has not been populated. So I used pointer manipulation for getting the tcphdr. This works fine. However when catching packets at POST_ROUTING, that is on the way out, all the headers, except MAC, are populated. However at times I used to get junk values whenever I tried using values from tcphdr directly.

This was solved by linearizing the sk_buff before manipulating it. So now I always do skb_linearize(skb, GFP_ATOMIC) at the start of the hook function.

2. At the PRE_ROUTING hook, I was not able to access the MAC header directly using skb->mac.eth. I could get the protocol value but not the hardware addr. I am not sure why this method didnt work.

This was solved by doing the following
struct ethhdr *mac = (struct ethhdr *)skb->mac.raw;

The idea being that one needs to typecast the memory properly. Now I can access the hardware source and dest addr from the variable mac. Easy right :->

3. I use skb_copy() to make a copy of the sk_buff. skb_copy() calls skb_linearize(), so there is no need to explicitly put a call for skb_linearize() in your code.

4. I got the following error while hacking the kernel

KERNEL: assertion (atomic_read(&skb->users) == 0) failed at dev.c

So what does this mean. Lets take a step back in order to understand this. sk_buff has a variable called 'users'. This variable stores the count of the number users (processes) that are accessing it. Functions like skb_get, _clone, _copy etc increment this variable. So this error says 'I am trying to read an sk_buff but it seems no one is using it i.e. the sk_buff in question has been freed'.

Why did this happen ? In my code, I forgot a return statement. After I called ip_finish_output() for putting the packet on the wire, I forgot the return. So it went into my error control messages and called kfree_skb(). Obviously the sk_buff is not there and so the error. Lesson learned: Be more careful while writing and have lots of patience.

5. How can one enable SLAB_DEBUGGING ?
Set CONFIG_DEBUG_SLAB = Y in your .config file
Then run 'make oldconfig' and recompile the kernel

If you try to write to a previously freed slab, the kernel will complain immediately. I was about to use this for checking why I was getting he error I discuss in 4.

I had a few interesting issues while creating a SYN for the connection (HB)->(HB, dest).

6. I make a copy of the original packet in my linked list called forward-queue (fwd-q). In the function that creates the SYN for fwd connection, I first make a copy of the sk_buff at the head of fwd-q and then make changes in that header. When I was trying to access the tcphdr values, I was getting junk.

What was I doing wrong ? I was copying the packet into the fwd-q before I pulled the tcphdr using pskb_may_pull. Because of this tcphdr was not populated and hence I could not access the fields directly.

7. I was trying to calculate tcp checksum by calling tcp_v4_check(). However I was getting wired results on the wire like fragmented packets, wrong checksum etc.

The solution was to set the checksum field of the header to zero before actually recalculating the checksum. I dont understand very clearly as to why this is required.

Another thing was that tcp_v4_check() makes use to skb->len. However I was not sure what value it contains in the copy. So I calculated length that tcp_v4_check() would need using iph->tot_len and iph->ihl. Remember tot_len is u16 and not u32, so use ntohs(). Sick error, but I made it. However, now that I think about it, skb->len should contain the proper value because I copy the packet after pulling the tcphdr. So len should be equal to data bytes.

8. Big problem. There are times when the code works like a gem and then there are times when it shows me Fragmented IP packet on the wire. Right now I have no clue why this happens. But need to get this fixed, else everything else is a waste.

Tuesday, April 05, 2005

To Do List

create the following variables in struct split_flow_info

1. tcp_topions of type tp_opt - This will hold all the info related to TCP options. Need to think if I need to create them or can I use tp_opt
2. prev_flow_hw of type ethhdr - This will store the hw src and dest addr of the incoming packet. I dont think that I would need a similar variable for the forward flow.