I'm working on a kernel module code, where I need to peek in to the
routing table to fetch ARP table entry for my daddr:
|--------------------------------------------------|
-------+ enp0s1 192.168.2.0/24 192.168.3.0/24 enp0s2 +-----
|--------------------------------------------------|
For example, I need to obtain neighbour entry for 192.168.3.111, and this entry has been permanently added in the table:
% ip neigh add 192.168.3.111 lladdr 00:11:22:33:44:55 dev enp0s2 nud permanent
% ip neigh sh
...
192.168.3.111 dev enp0s2 lladdr 00:11:22:33:44:55 PERMANENT
% ip route show
...
192.168.3.0/24 dev enp0s2 proto kernel scope link src 192.168.3.2
I came up with the following code:
struct rtable *rt;
struct flowi4 fl4;
struct dst_entry dst;
struct neighbour *neigh;
u8 mac[ETH_ALEN];
...
memset(&fl4, 0, sizeof fl4);
fl4.daddr = daddr;
fl4.flowi4_proto = IPPROTO_UDP;
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
goto err;
...
dst = rt->dst;
neigh = dst_neigh_lookup(&dst, &fl4.daddr);
if (!neigh) {
...
}
neigh_ha_snapshot(mac, neigh, neigh->dev);
neigh_release(neigh);
ip_rt_put(rt);
However neigh_ha_snapshot does not return correct MAC address, in fact I think it returns garbage, sometimes ff:ff:ff:ff:ff:ff, sometimes multicast 01:xx:xx:xx:xx:xx.
What am I doing wrong?
The issue is fixed as follows:
neigh = dst_neigh_lookup(&rt->dst, &fl4.daddr);
So instead of having struct dst_entry object on the stack, assigning a value from rt and passing a pointer to it in dst_neigh_lookup(), just pass a a pointer to dst member in the current rt object.
The reason is withing the following code:
static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
{
struct neighbour *n = dst->ops->neigh_lookup(dst, NULL, daddr);
return IS_ERR(n) ? NULL : n;
}
where neigh_lookup is initialized to function ipv4_neigh_lookup() defined in net/ipv4/route.c :
static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
struct sk_buff *skb,
const void *daddr)
{
struct net_device *dev = dst->dev;
const __be32 *pkey = daddr;
const struct rtable *rt;
struct neighbour *n;
rt = (const struct rtable *) dst;
...
}
From this point rt is bogus and so is the rest.
Related
I am trying to create a TC program that will clone a packet, encapsulate it with a modified L3 header and send the clone to a different host ("Monitor host") - Can I do that using a combination of bpf_skb_adjust_room with bpf_clone_redirect?
Kernel examples do not shed too much details into this use-case (for example, here.)
My current attempt seems to be mutating the original packet:
// Represents the redirect destination.
struct destination {
__u32 destination_ip;
__u8 destination_mac[ETH_ALEN];
};
// Contains the destination to redirect traffic to.
struct bpf_map_def SEC("maps") destinations = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(struct destination),
.max_entries = 1,
.map_flags = BPF_F_NO_PREALLOC,
};
SEC("tc")
int tc_ingress(struct __sk_buff *skb) {
__u32 key = 0;
struct destination *dest = bpf_map_lookup_elem(&destinations, &key);
if (dest != NULL) {
void *data_end = (void *)(long)skb->data_end;
void *data = (void *)(long)skb->data;
// Necessary validation: if L3 layer does not exist, ignore and continue.
if (data + sizeof(struct ethhdr) > data_end) {
return TC_ACT_OK;
}
struct ethhdr *eth = data;
struct iphdr encapsulate_iphdr = {};
struct iphdr *original_iphdr = data + sizeof(struct ethhdr);
if ((void*) original_iphdr + sizeof(struct iphdr) > data_end) {
return TC_ACT_OK;
}
// Change the L2 destination to the provided MAC destination
// and the source to the MAC addr of the recieving host.
memcpy(ð->h_source, ð->h_dest, ETH_ALEN);
memcpy(ð->h_dest, dest->destination_mac, ETH_ALEN);
// Change the L3 destination to the provided destination IP
// and the source to the ip addr of the recieving host.
memcpy(&encapsulate_iphdr.daddr, &dest->destination_ip, IPV4_ADDR_LEN);
memcpy(&encapsulate_iphdr.saddr, &original_iphdr->daddr, IPV4_ADDR_LEN);
// Adjust room for another iphdr after the L2 layer.
if (bpf_skb_adjust_room(skb, sizeof(struct iphdr), BPF_ADJ_ROOM_NET, 0)) {
return TC_ACT_OK;
}
// Store the headers at after L2 headers at the original headers offset.
unsigned long offset = (unsigned long) original_iphdr;
if (bpf_skb_store_bytes(skb, (int)offset, &encapsulate_iphdr, sizeof(struct iphdr), 0)) {
return TC_ACT_OK;
}
// route back the to egress path.
// Zero flag means that the socket buffer is
// cloned to the iface egress path.
bpf_clone_redirect(skb, skb->ifindex, 0);
}
return TC_ACT_OK;
}
I believe that's not possible within the same BPF program run today because bpf_clone_redirect will redirect the clone as soon as it's called and there is not clone helper that wouldn't redirect as well.
You could however implement this with a recirculation to the same interface. The pseudo code would look something like:
if (skb->mark == ORIGINAL_PACKET) {
skb->mark = 0;
return TC_ACT_OK;
}
skb->mark = ORIGINAL_PACKET;
bpf_clone_redirect(skb, skb->ifindex, BPF_F_INGRESS);
skb->mark = 0;
... implement changes ...
return bpf_redirect(skb, skb->ifindex, 0);
Is it possible to set the values of a struct pointer in a struct? I get an error and cannot typecast myStruct* into myStruct.
typedef struct {
int foo;
int bar;
} myStruct;
int main() {
myStruct *pS;
myStruct S1 = {0,0};
myStruct S2;
pS = S1;
S2 = pS; // I get an error there, cannot set struct pointer to a struct
}
So, in your example, you have pointer pS and regular variable S1.
A pointer is a variable that stores the memory address as its value.
Variable is the name of memory location.
So, the difference between regular variable is that variable stores value of an object, but pointer stores memory address of an object.
There are operators which allow getting object's address and getting object value by it's address:
Address-of operator &. &a will return address of object a.
Dereference operator *. *p will return object stored by address p.
Thus, in your code you should get two errors:
pS = S1; // error: Trying to assign struct value to a pointer
S2 = pS; // error: Trying to assign pointer to a struct value
To fix this, you should assign address to a pS and value to S2
typedef struct {
int foo;
int bar;
} myStruct;
int main() {
myStruct *pS;
myStruct S1 = {0,0};
myStruct S2;
pS = &S1; // getting address of S1
S2 = *pS; // getting value stored by address pS
}
When I'm trying to compile below program I'm getting error as request for member "machine" in something not a structure or union
struct machine
{
int a;
int b;
int c;
};
struct config
{
struct machine *machine;
int n;
};
int main()
{
struct config *conf;
struct machine *mach;
mach->a=1;
mach->b=2;
mach->c=3;
conf.machine=mach; /* error in this line */
return 0;
}
Can anyone help me in fixing this bug.. Thanks in advance!!!
conf is a pointer, not a structure, so you have to dereference it, just like you did with mach.
conf->machine = mach;
Also, you need to allocate memory for both conf and mach.
I'm trying to use a file pointer that I have declared in a structure of linked list, but I keep getting it as a NULL value.
I have the following structure:
struct _hash_table
{
char found;
struct _hash_chain *hash_chain;
}
struct _hash_chain
{
uint64_t value;
FILE *fout;
struct _hash_chain *next;
}
and
struct _hash_table hash_table[TABLE_SIZE];
I keep getting hash_table[i]->hash_chain->fout = NULL and it's pointer address is nil.
Do I need to dynamically allocate memory for the pointer?
struct _hash_table hash_table[TABLE_SIZE]; - This will not allocate memory for struct _hash_chain because hash_chain is pointer variable in _hash_table.
...
struct _hash_table hash_table[TABLE_SIZE];
for (i = 0; i < TABLE_SIZE; i++);
{
hash_table[i].hash_chain = (struct _hash_chain *)malloc(sizeof(struct _hash_chain));
memset(hash_table[i].hash_chain, 0, sizeof(struct _hash_chain));
}
//Then do file open for TABLE_SIZE times
//hash_table[0].hash_chain->fout = fopen("file.txt", "w");
...
Accssing h_table[i].hash_chain without dynamic memory allocation will leads to crash(an undefined behaviour). I hope you will take care of next pointer.
#include<stdio.h>
#include<stdlib.h>
/* Link list node */
struct node
{
int data;
struct node *next;
};
/* Function to reverse the linked list */
static void reverse(struct node** head_ref)
{
struct node *prev = NULL;
struct node *current = *head_ref;
struct node *next;
while (current != NULL)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head_ref = prev;
}
What are the lines that start with struct in the reverse function responsible of?
do they extend the original struct or creating new structs that the original struct pointing to? I don't really understand why there is no name to the original struct
Is there a diffrence between struct node *next; and struct node* next; ?
Line struct node *prev is declaration of variable prev of type "pointer to struct node". These lines just declare some local variables. prev contains a pointer to the last processed node, current contains a pointer to the currently processing node and next is used to save a pointer to the next node of original list.
There's no difference between struct node *next and struct node* next.
#willys is right. As we know struts is group of similar and un-similar datatype.When struct is created , it allocates a block of memory.And that memory has an address.
struct node{
int age;
char name[20];
struct node *next_address; //Address of its type (self referential structure)
}
This above struct allocates a block of memory . Inside this block 3 different data is storing (age,name and a address of structure node)
When you want to store more blocks (for storing more data ) , you need to allocate more struct.But, there is a problem when all structs are allocated in memory , they don't have any relation between each other.Its a cause of memory leak.
So, keep the address field on each block of allocated memory, so that any block of memory can store the address of its nearest block.
Its , the real flavor value of Linked List.So, there is no confusion about the name of the struct.