Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-28 Thread Christina Jacob
On Wed, Oct 11, 2017 at 3:07 AM, David Daney  wrote:
> On 10/10/2017 10:19 AM, Stephen Hemminger wrote:
>>
>> On Tue, 10 Oct 2017 12:58:52 +0530
>> Christina Jacob  wrote:
>>
>>> +/* Get the mac address of the interface given interface name */
>>> +static long *getmac(char *iface)
>>> +{
>>> +   int fd;
>>> +   struct ifreq ifr;
>>> +   long *mac = NULL;
>>> +
>>> +   fd = socket(AF_INET, SOCK_DGRAM, 0);
>>> +   ifr.ifr_addr.sa_family = AF_INET;
>>> +   strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
>>> +   ioctl(fd, SIOCGIFHWADDR, );
>>> +   mac = (long *)ifr.ifr_hwaddr.sa_data;
>>> +   close(fd);
>>> +   return mac;
>>
>>
>> Always check return value of ioctl.
>> You are assuming sizeof(long) > 6 bytes.
>> Also the byte order.
>
>
>
> Also:
>
> Returning the address of a local variable (ifr.ifr_hwaddr.sa_data), and then
> dereferencing it outside of the function is not correct.
>
> The casting of the char sa_data[] to a long * may cause alignment faults on
> some architectures.  The may also be endinaness issues depending on how the
> data are manipulated if you pack all those chars into a long.
>
> If we think that a MAC address is char[6], then it may be best to define the
> data structures as such and manipulate it as an array instead of trying to
> pack it into a long.

How do I feed the MAC address to xdp.data ? Is it ok to do a manual
leftshift + biwise and  for the purpose?

>
> Keep working on this though, this program will surely be useful.
>
> David Daney


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-28 Thread Christina Jacob
On Wed, Oct 11, 2017 at 3:07 AM, David Daney  wrote:
> On 10/10/2017 10:19 AM, Stephen Hemminger wrote:
>>
>> On Tue, 10 Oct 2017 12:58:52 +0530
>> Christina Jacob  wrote:
>>
>>> +/* Get the mac address of the interface given interface name */
>>> +static long *getmac(char *iface)
>>> +{
>>> +   int fd;
>>> +   struct ifreq ifr;
>>> +   long *mac = NULL;
>>> +
>>> +   fd = socket(AF_INET, SOCK_DGRAM, 0);
>>> +   ifr.ifr_addr.sa_family = AF_INET;
>>> +   strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
>>> +   ioctl(fd, SIOCGIFHWADDR, );
>>> +   mac = (long *)ifr.ifr_hwaddr.sa_data;
>>> +   close(fd);
>>> +   return mac;
>>
>>
>> Always check return value of ioctl.
>> You are assuming sizeof(long) > 6 bytes.
>> Also the byte order.
>
>
>
> Also:
>
> Returning the address of a local variable (ifr.ifr_hwaddr.sa_data), and then
> dereferencing it outside of the function is not correct.
>
> The casting of the char sa_data[] to a long * may cause alignment faults on
> some architectures.  The may also be endinaness issues depending on how the
> data are manipulated if you pack all those chars into a long.
>
> If we think that a MAC address is char[6], then it may be best to define the
> data structures as such and manipulate it as an array instead of trying to
> pack it into a long.

How do I feed the MAC address to xdp.data ? Is it ok to do a manual
leftshift + biwise and  for the purpose?

>
> Keep working on this though, this program will surely be useful.
>
> David Daney


RE: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-11 Thread David Laight
From: Jesper Dangaard Brouer
> Sent: 10 October 2017 20:06
...
> > +   int src_ip = 0, dest_ip = 0;
...
> > +   key4.b8[4] = dest_ip % 0x100;
> > +   key4.b8[5] = (dest_ip >> 8) % 0x100;
> > +   key4.b8[6] = (dest_ip >> 16) % 0x100;
> > +   key4.b8[7] = (dest_ip >> 24) % 0x100;

Do you really want signed remainders done here?

David



RE: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-11 Thread David Laight
From: Jesper Dangaard Brouer
> Sent: 10 October 2017 20:06
...
> > +   int src_ip = 0, dest_ip = 0;
...
> > +   key4.b8[4] = dest_ip % 0x100;
> > +   key4.b8[5] = (dest_ip >> 8) % 0x100;
> > +   key4.b8[6] = (dest_ip >> 16) % 0x100;
> > +   key4.b8[7] = (dest_ip >> 24) % 0x100;

Do you really want signed remainders done here?

David



Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread David Daney

On 10/10/2017 10:19 AM, Stephen Hemminger wrote:

On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:


+/* Get the mac address of the interface given interface name */
+static long *getmac(char *iface)
+{
+   int fd;
+   struct ifreq ifr;
+   long *mac = NULL;
+
+   fd = socket(AF_INET, SOCK_DGRAM, 0);
+   ifr.ifr_addr.sa_family = AF_INET;
+   strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
+   ioctl(fd, SIOCGIFHWADDR, );
+   mac = (long *)ifr.ifr_hwaddr.sa_data;
+   close(fd);
+   return mac;


Always check return value of ioctl.
You are assuming sizeof(long) > 6 bytes.
Also the byte order.



Also:

Returning the address of a local variable (ifr.ifr_hwaddr.sa_data), and 
then dereferencing it outside of the function is not correct.


The casting of the char sa_data[] to a long * may cause alignment faults 
on some architectures.  The may also be endinaness issues depending on 
how the data are manipulated if you pack all those chars into a long.


If we think that a MAC address is char[6], then it may be best to define 
the data structures as such and manipulate it as an array instead of 
trying to pack it into a long.


Keep working on this though, this program will surely be useful.

David Daney


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread David Daney

On 10/10/2017 10:19 AM, Stephen Hemminger wrote:

On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:


+/* Get the mac address of the interface given interface name */
+static long *getmac(char *iface)
+{
+   int fd;
+   struct ifreq ifr;
+   long *mac = NULL;
+
+   fd = socket(AF_INET, SOCK_DGRAM, 0);
+   ifr.ifr_addr.sa_family = AF_INET;
+   strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
+   ioctl(fd, SIOCGIFHWADDR, );
+   mac = (long *)ifr.ifr_hwaddr.sa_data;
+   close(fd);
+   return mac;


Always check return value of ioctl.
You are assuming sizeof(long) > 6 bytes.
Also the byte order.



Also:

Returning the address of a local variable (ifr.ifr_hwaddr.sa_data), and 
then dereferencing it outside of the function is not correct.


The casting of the char sa_data[] to a long * may cause alignment faults 
on some architectures.  The may also be endinaness issues depending on 
how the data are manipulated if you pack all those chars into a long.


If we think that a MAC address is char[6], then it may be best to define 
the data structures as such and manipulate it as an array instead of 
trying to pack it into a long.


Keep working on this though, this program will surely be useful.

David Daney


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Jesper Dangaard Brouer
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> +SEC("xdp3")
> +int xdp_prog3(struct xdp_md *ctx)
> +{
> + void *data_end = (void *)(long)ctx->data_end;
> + void *data = (void *)(long)ctx->data;
> + struct ethhdr *eth = data;
> + int rc = XDP_DROP, forward_to;
> + long *value;
> + struct trie_value *prefix_value;
> + long *dest_mac = NULL, *src_mac = NULL;
> + u16 h_proto;
> + u64 nh_off;
> + u32 ipproto;
> + union key_4 key4;

Reverse-xmas tree rule: Prefer ordering declarations longest to shortest.


[...]
> + if (h_proto == htons(ETH_P_ARP)) {
> + return XDP_PASS;
> + } else if (h_proto == htons(ETH_P_IP)) {
> + int src_ip = 0, dest_ip = 0;
> + struct direct_map *direct_entry;
> +
> + ipproto = parse_ipv4(data, nh_off, data_end, _ip, _ip);
> + direct_entry = (struct direct_map *)bpf_map_lookup_elem
> + (_match, _ip);
> + /*check for exact match, this would give a faster lookup*/
> + if (direct_entry && direct_entry->mac && direct_entry->arp.mac) 
> {
> + src_mac = _entry->mac;
> + dest_mac = _entry->arp.mac;
> + forward_to = direct_entry->ifindex;
> + } else {
> + /*Look up in the trie for lpm*/
> + key4.b32[0] = 32;
> + key4.b8[4] = dest_ip % 0x100;
> + key4.b8[5] = (dest_ip >> 8) % 0x100;
> + key4.b8[6] = (dest_ip >> 16) % 0x100;
> + key4.b8[7] = (dest_ip >> 24) % 0x100;
> + prefix_value = ((struct trie_value *)bpf_map_lookup_elem
> + (_map, ));
> + if (!prefix_value) {
> + return XDP_DROP;
> + } else {
> + src_mac = _value->value;
> + if (src_mac) {
> + dest_mac = (long *)bpf_map_lookup_elem
> + (_table, _ip);
> + if (!dest_mac) {
> + if (prefix_value->gw) {
> + dest_ip = *(__be32 
> *)_value->gw;
> + dest_mac = (long 
> *)bpf_map_lookup_elem(_table, _ip);
> + } else {
> + return XDP_DROP;
> + }
> + }
> + forward_to = prefix_value->ifindex;
> + } else {
> + return XDP_DROP;
> + }
> + }
> + }
> + } else {
> + ipproto = 0;
> + }

The nesting in this function is getting annoying to read.
Kernel code often use "early return" style coding to solve this.

A quick search turns up this guide, look at section "Early return"
 
https://en.wikibooks.org/wiki/Computer_Programming/Coding_Style/Minimize_nesting

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Jesper Dangaard Brouer
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> +SEC("xdp3")
> +int xdp_prog3(struct xdp_md *ctx)
> +{
> + void *data_end = (void *)(long)ctx->data_end;
> + void *data = (void *)(long)ctx->data;
> + struct ethhdr *eth = data;
> + int rc = XDP_DROP, forward_to;
> + long *value;
> + struct trie_value *prefix_value;
> + long *dest_mac = NULL, *src_mac = NULL;
> + u16 h_proto;
> + u64 nh_off;
> + u32 ipproto;
> + union key_4 key4;

Reverse-xmas tree rule: Prefer ordering declarations longest to shortest.


[...]
> + if (h_proto == htons(ETH_P_ARP)) {
> + return XDP_PASS;
> + } else if (h_proto == htons(ETH_P_IP)) {
> + int src_ip = 0, dest_ip = 0;
> + struct direct_map *direct_entry;
> +
> + ipproto = parse_ipv4(data, nh_off, data_end, _ip, _ip);
> + direct_entry = (struct direct_map *)bpf_map_lookup_elem
> + (_match, _ip);
> + /*check for exact match, this would give a faster lookup*/
> + if (direct_entry && direct_entry->mac && direct_entry->arp.mac) 
> {
> + src_mac = _entry->mac;
> + dest_mac = _entry->arp.mac;
> + forward_to = direct_entry->ifindex;
> + } else {
> + /*Look up in the trie for lpm*/
> + key4.b32[0] = 32;
> + key4.b8[4] = dest_ip % 0x100;
> + key4.b8[5] = (dest_ip >> 8) % 0x100;
> + key4.b8[6] = (dest_ip >> 16) % 0x100;
> + key4.b8[7] = (dest_ip >> 24) % 0x100;
> + prefix_value = ((struct trie_value *)bpf_map_lookup_elem
> + (_map, ));
> + if (!prefix_value) {
> + return XDP_DROP;
> + } else {
> + src_mac = _value->value;
> + if (src_mac) {
> + dest_mac = (long *)bpf_map_lookup_elem
> + (_table, _ip);
> + if (!dest_mac) {
> + if (prefix_value->gw) {
> + dest_ip = *(__be32 
> *)_value->gw;
> + dest_mac = (long 
> *)bpf_map_lookup_elem(_table, _ip);
> + } else {
> + return XDP_DROP;
> + }
> + }
> + forward_to = prefix_value->ifindex;
> + } else {
> + return XDP_DROP;
> + }
> + }
> + }
> + } else {
> + ipproto = 0;
> + }

The nesting in this function is getting annoying to read.
Kernel code often use "early return" style coding to solve this.

A quick search turns up this guide, look at section "Early return"
 
https://en.wikibooks.org/wiki/Computer_Programming/Coding_Style/Minimize_nesting

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Stephen Hemminger
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> + bzero(, sizeof(route));
> + bzero(dsts, sizeof(dsts));
> + bzero(dsts_len, sizeof(dsts_len));
> + bzero(gws, sizeof(gws));
> + bzero(ifs, sizeof(ifs));
> + bzero(, sizeof(route));

This is all unnecessary.
It looks like you write OpenBSD security code.
Only a security person would zero stack variables before return
and only BSD people use bzero(), Linux style is to use memset.


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Stephen Hemminger
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> + bzero(, sizeof(route));
> + bzero(dsts, sizeof(dsts));
> + bzero(dsts_len, sizeof(dsts_len));
> + bzero(gws, sizeof(gws));
> + bzero(ifs, sizeof(ifs));
> + bzero(, sizeof(route));

This is all unnecessary.
It looks like you write OpenBSD security code.
Only a security person would zero stack variables before return
and only BSD people use bzero(), Linux style is to use memset.


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Stephen Hemminger
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> +/* Get the mac address of the interface given interface name */
> +static long *getmac(char *iface)
> +{
> + int fd;
> + struct ifreq ifr;
> + long *mac = NULL;
> +
> + fd = socket(AF_INET, SOCK_DGRAM, 0);
> + ifr.ifr_addr.sa_family = AF_INET;
> + strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
> + ioctl(fd, SIOCGIFHWADDR, );
> + mac = (long *)ifr.ifr_hwaddr.sa_data;
> + close(fd);
> + return mac;

Always check return value of ioctl.
You are assuming sizeof(long) > 6 bytes.
Also the byte order.


Re: [PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Stephen Hemminger
On Tue, 10 Oct 2017 12:58:52 +0530
Christina Jacob  wrote:

> +/* Get the mac address of the interface given interface name */
> +static long *getmac(char *iface)
> +{
> + int fd;
> + struct ifreq ifr;
> + long *mac = NULL;
> +
> + fd = socket(AF_INET, SOCK_DGRAM, 0);
> + ifr.ifr_addr.sa_family = AF_INET;
> + strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
> + ioctl(fd, SIOCGIFHWADDR, );
> + mac = (long *)ifr.ifr_hwaddr.sa_data;
> + close(fd);
> + return mac;

Always check return value of ioctl.
You are assuming sizeof(long) > 6 bytes.
Also the byte order.


[PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Christina Jacob
Implements port to port forwarding with route table and arp table
lookup for ipv4 packets using bpf_redirect helper function and
lpm_trie  map.

Signed-off-by: Christina Jacob 
---
 samples/bpf/Makefile   |4 +
 samples/bpf/xdp_router_ipv4_kern.c |  189 +++
 samples/bpf/xdp_router_ipv4_user.c |  655 
 3 files changed, 848 insertions(+), 0 deletions(-)
 create mode 100644 samples/bpf/xdp_router_ipv4_kern.c
 create mode 100644 samples/bpf/xdp_router_ipv4_user.c

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index cf17c79..8504ebb 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -28,6 +28,7 @@ hostprogs-y += test_cgrp2_sock
 hostprogs-y += test_cgrp2_sock2
 hostprogs-y += xdp1
 hostprogs-y += xdp2
+hostprogs-y += xdp_router_ipv4
 hostprogs-y += test_current_task_under_cgroup
 hostprogs-y += trace_event
 hostprogs-y += sampleip
@@ -73,6 +74,7 @@ test_cgrp2_sock2-objs := bpf_load.o $(LIBBPF) 
test_cgrp2_sock2.o
 xdp1-objs := bpf_load.o $(LIBBPF) xdp1_user.o
 # reuse xdp1 source intentionally
 xdp2-objs := bpf_load.o $(LIBBPF) xdp1_user.o
+xdp_router_ipv4-objs := bpf_load.o $(LIBBPF) xdp_router_ipv4_user.o
 test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) cgroup_helpers.o \
   test_current_task_under_cgroup_user.o
 trace_event-objs := bpf_load.o $(LIBBPF) trace_event_user.o
@@ -114,6 +116,7 @@ always += parse_varlen.o parse_simple.o parse_ldabs.o
 always += test_cgrp2_tc_kern.o
 always += xdp1_kern.o
 always += xdp2_kern.o
+always += xdp_router_ipv4_kern.o
 always += test_current_task_under_cgroup_kern.o
 always += trace_event_kern.o
 always += sampleip_kern.o
@@ -160,6 +163,7 @@ HOSTLOADLIBES_map_perf_test += -lelf -lrt
 HOSTLOADLIBES_test_overhead += -lelf -lrt
 HOSTLOADLIBES_xdp1 += -lelf
 HOSTLOADLIBES_xdp2 += -lelf
+HOSTLOADLIBES_xdp_router_ipv4 += -lelf
 HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
 HOSTLOADLIBES_trace_event += -lelf
 HOSTLOADLIBES_sampleip += -lelf
diff --git a/samples/bpf/xdp_router_ipv4_kern.c 
b/samples/bpf/xdp_router_ipv4_kern.c
new file mode 100644
index 000..c2bfe40
--- /dev/null
+++ b/samples/bpf/xdp_router_ipv4_kern.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+#define KBUILD_MODNAME "foo"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "bpf_helpers.h"
+#include 
+#include 
+
+struct trie_value {
+   __u8 prefix[4];
+   long value;
+   int gw;
+   int ifindex;
+   int metric;
+};
+
+/*Key for lpm_trie*/
+union key_4 {
+   u32 b32[2];
+   u8 b8[8];
+};
+
+struct arp_entry {
+   int dst;
+   long mac;
+};
+
+struct direct_map {
+   long mac;
+   int ifindex;
+   struct arp_entry arp;
+};
+
+/* Map for trie implementation*/
+struct bpf_map_def SEC("maps") lpm_map = {
+   .type = BPF_MAP_TYPE_LPM_TRIE,
+   .key_size = 8,
+   .value_size = sizeof(struct trie_value),
+   .max_entries = 50,
+   .map_flags = BPF_F_NO_PREALLOC,
+};
+
+/* Map for counter*/
+struct bpf_map_def SEC("maps") rxcnt = {
+   .type = BPF_MAP_TYPE_PERCPU_ARRAY,
+   .key_size = sizeof(u32),
+   .value_size = sizeof(long),
+   .max_entries = 256,
+};
+
+/* Map for ARP table*/
+struct bpf_map_def SEC("maps") arp_table = {
+   .type = BPF_MAP_TYPE_HASH,
+   .key_size = sizeof(int),
+   .value_size = sizeof(long),
+   .max_entries = 50,
+};
+
+/* Map to keep the exact match entries in the route table*/
+struct bpf_map_def SEC("maps") exact_match = {
+   .type = BPF_MAP_TYPE_HASH,
+   .key_size = sizeof(int),
+   .value_size = sizeof(struct direct_map),
+   .max_entries = 50,
+};
+
+/* Function to set source and destination mac of the packet */
+static inline void set_src_dst_mac(void *data, void *src, void *dst)
+{
+   unsigned short *p  = data;
+   unsigned short *dest   = dst;
+   unsigned short *source = src;
+
+   __builtin_memcpy(p, dest, 3);
+   __builtin_memcpy(p + 3, source, 3);
+}
+
+/* Parse IPV4 packet to get SRC, DST IP and protocol */
+static inline int parse_ipv4(void *data, u64 nh_off, void *data_end,
+__be32 *src, __be32 *dest)
+{
+   struct iphdr *iph = data + nh_off;
+
+   if (iph + 1 > data_end)
+   return 0;
+   *src = (__be32)iph->saddr;
+   *dest = (__be32)iph->daddr;
+   return iph->protocol;
+}
+
+SEC("xdp3")
+int xdp_prog3(struct xdp_md *ctx)
+{
+   void *data_end = (void *)(long)ctx->data_end;
+   void *data = (void *)(long)ctx->data;
+   struct ethhdr *eth = data;
+   int rc = XDP_DROP, forward_to;
+   long *value;
+   struct trie_value *prefix_value;
+ 

[PATCH v2] xdp: Sample xdp program implementing ip forward

2017-10-10 Thread Christina Jacob
Implements port to port forwarding with route table and arp table
lookup for ipv4 packets using bpf_redirect helper function and
lpm_trie  map.

Signed-off-by: Christina Jacob 
---
 samples/bpf/Makefile   |4 +
 samples/bpf/xdp_router_ipv4_kern.c |  189 +++
 samples/bpf/xdp_router_ipv4_user.c |  655 
 3 files changed, 848 insertions(+), 0 deletions(-)
 create mode 100644 samples/bpf/xdp_router_ipv4_kern.c
 create mode 100644 samples/bpf/xdp_router_ipv4_user.c

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index cf17c79..8504ebb 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -28,6 +28,7 @@ hostprogs-y += test_cgrp2_sock
 hostprogs-y += test_cgrp2_sock2
 hostprogs-y += xdp1
 hostprogs-y += xdp2
+hostprogs-y += xdp_router_ipv4
 hostprogs-y += test_current_task_under_cgroup
 hostprogs-y += trace_event
 hostprogs-y += sampleip
@@ -73,6 +74,7 @@ test_cgrp2_sock2-objs := bpf_load.o $(LIBBPF) 
test_cgrp2_sock2.o
 xdp1-objs := bpf_load.o $(LIBBPF) xdp1_user.o
 # reuse xdp1 source intentionally
 xdp2-objs := bpf_load.o $(LIBBPF) xdp1_user.o
+xdp_router_ipv4-objs := bpf_load.o $(LIBBPF) xdp_router_ipv4_user.o
 test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) cgroup_helpers.o \
   test_current_task_under_cgroup_user.o
 trace_event-objs := bpf_load.o $(LIBBPF) trace_event_user.o
@@ -114,6 +116,7 @@ always += parse_varlen.o parse_simple.o parse_ldabs.o
 always += test_cgrp2_tc_kern.o
 always += xdp1_kern.o
 always += xdp2_kern.o
+always += xdp_router_ipv4_kern.o
 always += test_current_task_under_cgroup_kern.o
 always += trace_event_kern.o
 always += sampleip_kern.o
@@ -160,6 +163,7 @@ HOSTLOADLIBES_map_perf_test += -lelf -lrt
 HOSTLOADLIBES_test_overhead += -lelf -lrt
 HOSTLOADLIBES_xdp1 += -lelf
 HOSTLOADLIBES_xdp2 += -lelf
+HOSTLOADLIBES_xdp_router_ipv4 += -lelf
 HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
 HOSTLOADLIBES_trace_event += -lelf
 HOSTLOADLIBES_sampleip += -lelf
diff --git a/samples/bpf/xdp_router_ipv4_kern.c 
b/samples/bpf/xdp_router_ipv4_kern.c
new file mode 100644
index 000..c2bfe40
--- /dev/null
+++ b/samples/bpf/xdp_router_ipv4_kern.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+#define KBUILD_MODNAME "foo"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "bpf_helpers.h"
+#include 
+#include 
+
+struct trie_value {
+   __u8 prefix[4];
+   long value;
+   int gw;
+   int ifindex;
+   int metric;
+};
+
+/*Key for lpm_trie*/
+union key_4 {
+   u32 b32[2];
+   u8 b8[8];
+};
+
+struct arp_entry {
+   int dst;
+   long mac;
+};
+
+struct direct_map {
+   long mac;
+   int ifindex;
+   struct arp_entry arp;
+};
+
+/* Map for trie implementation*/
+struct bpf_map_def SEC("maps") lpm_map = {
+   .type = BPF_MAP_TYPE_LPM_TRIE,
+   .key_size = 8,
+   .value_size = sizeof(struct trie_value),
+   .max_entries = 50,
+   .map_flags = BPF_F_NO_PREALLOC,
+};
+
+/* Map for counter*/
+struct bpf_map_def SEC("maps") rxcnt = {
+   .type = BPF_MAP_TYPE_PERCPU_ARRAY,
+   .key_size = sizeof(u32),
+   .value_size = sizeof(long),
+   .max_entries = 256,
+};
+
+/* Map for ARP table*/
+struct bpf_map_def SEC("maps") arp_table = {
+   .type = BPF_MAP_TYPE_HASH,
+   .key_size = sizeof(int),
+   .value_size = sizeof(long),
+   .max_entries = 50,
+};
+
+/* Map to keep the exact match entries in the route table*/
+struct bpf_map_def SEC("maps") exact_match = {
+   .type = BPF_MAP_TYPE_HASH,
+   .key_size = sizeof(int),
+   .value_size = sizeof(struct direct_map),
+   .max_entries = 50,
+};
+
+/* Function to set source and destination mac of the packet */
+static inline void set_src_dst_mac(void *data, void *src, void *dst)
+{
+   unsigned short *p  = data;
+   unsigned short *dest   = dst;
+   unsigned short *source = src;
+
+   __builtin_memcpy(p, dest, 3);
+   __builtin_memcpy(p + 3, source, 3);
+}
+
+/* Parse IPV4 packet to get SRC, DST IP and protocol */
+static inline int parse_ipv4(void *data, u64 nh_off, void *data_end,
+__be32 *src, __be32 *dest)
+{
+   struct iphdr *iph = data + nh_off;
+
+   if (iph + 1 > data_end)
+   return 0;
+   *src = (__be32)iph->saddr;
+   *dest = (__be32)iph->daddr;
+   return iph->protocol;
+}
+
+SEC("xdp3")
+int xdp_prog3(struct xdp_md *ctx)
+{
+   void *data_end = (void *)(long)ctx->data_end;
+   void *data = (void *)(long)ctx->data;
+   struct ethhdr *eth = data;
+   int rc = XDP_DROP, forward_to;
+   long *value;
+   struct trie_value *prefix_value;
+   long *dest_mac =