When the netlink packet comes to the kernel, as explained earlier, the doit function in the inet_rtnetlink_table indexed by RTM_NEWROUTE is called and control reaches inet_rtm_newroute() in net/ipv4/fib_frontend.c
int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct fib_table * tb;
struct rtattr **rta = arg;
struct rtmsg *r = NLMSG_DATA(nlh);
if (inet_check_attr(r, rta))
return -EINVAL;
tb = fib_new_table(r->rtm_table);
if (tb)
return tb->tb_insert(tb, r,(struct kern_rta*)rta,nlh,&NETLINK_CB(skb));
return -ENOBUFS;
}
NLMSG_DATA macro takes you to the start of the rtmessage in tha netlink packet.
inet_check_attr essentially loops through the parameter list and creates an array of parameters consisting of only the data, this is important because this is later typecasted to struct kern_rta in include/net/fib.h
struct kern_rta
{
void *rta_dst;
void *rta_src;
int *rta_iif;
int *rta_oif;
void *rta_gw;
u32 *rta_priority;
void *rta_prefsrc;
struct rtattr *rta_mx;
struct rtattr *rta_mp;
unsigned char *rta_protoinfo;
unsigned char *rta_flow;
struct rta_cacheinfo *rta_ci;
};
Note that this structure has a one to one correspondance with the routing table attributes so that the typecasting makes sense.
enum rtattr_type_t
{
RTA_UNSPEC,
RTA_DST,
RTA_SRC,
RTA_IIF,
RTA_OIF,
RTA_GATEWAY,
RTA_PRIORITY,
RTA_PREFSRC,
RTA_METRICS,
RTA_MULTIPATH,
RTA_PROTOINFO,
RTA_FLOW,
RTA_CACHEINFO
};
static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
{
int i;
for (i=1; i<=RTA_MAX; i++) {
struct rtattr *attr = rta[i-1];
.
.
if (i != RTA_MULTIPATH && i != RTA_METRICS)
rta[i-1] = (struct rtattr*)RTA_DATA(attr);
}
}
return 0;
}
A new fib_table is created, for this the RT_TABLE_MAIN parameter is used and the insert is a function pointer which takes us to fn_hash_insert() in net/ipv4/fib_hash.c, here the individual parameters are extracted and the entry added to the forwarding information base in the kernel.
So, as said earlier, to pack a netlink packet, the corresponding code in the kernel has to be understood for the right interpretation of the packets. To perform a specific function, the kernel expects the netlink packet to be packaged in a particular format, so from the user space the parameters have to be filled in that order for them to make sense in the kernel.