[ovs-discuss] Generating arp reply from GRE tunnel port (kernel space)
LIU Binghan
binghanluc at gmail.com
Tue Jun 12 15:12:45 UTC 2012
Hi,
I am developing a feature about GRE tunnel, when a gre port receive a ARP request, it will generate a ARP reply automatically. The ARP reply packet format that I generated is right (check it from wireshark). However, when I send the packet back to OVS, kernel panic happens. I think it caused by socket buffer problem, but I have no solution. Does anybody have some suggestion, or some book to recommend about this part. I will be very thankful for it.
Here is the code, the code with big font size is my modification.
int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
const struct tnl_mutable_config *mutable,*mut;
enum vport_err_type err = VPORT_E_TX_ERROR;
struct rtable *rt;
struct dst_entry *unattached_dst = NULL;
struct tnl_cache *cache;
int sent_len = 0;
__be16 frag_off = 0;
u8 ttl;
u8 inner_tos;
u8 tos;
mutable= rcu_dereference(tnl_vport->mutable);
/*ARP proxy for GRE tunnel*/
struct vport *arport;
struct ethhdr *eh;
struct arphdr *ah;
unsigned char *arp_ptr;
const unsigned char dummy_eh_source[ETH_ALEN]={0x11,0x11,0x11,0x11,0x11,0x11};
unsigned char ip_temp[4];
/* Validate the protocol headers before we try to use them. */
if (skb->protocol == htons(ETH_P_8021Q) &&
!vlan_tx_tag_present(skb)) {
if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
goto error_free;
skb->protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
skb_set_network_header(skb, VLAN_ETH_HLEN);
}
if (skb->protocol == htons(ETH_P_IP)) {
if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
+ sizeof(struct iphdr))))
skb->protocol = 0;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6)) {
if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
+ sizeof(struct ipv6hdr))))
skb->protocol = 0;
}
#endif
/* ToS */
if (skb->protocol == htons(ETH_P_IP))
inner_tos = ip_hdr(skb)->tos;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
inner_tos = ipv6_get_dsfield(ipv6_hdr(skb));
#endif
else
inner_tos = 0;
if (mutable->flags & TNL_F_TOS_INHERIT)
tos = inner_tos;
else
tos = mutable->tos;
tos = INET_ECN_encapsulate(tos, inner_tos);
/* Route lookup */
rt = find_route(vport, mutable, tos, &cache);
if (unlikely(!rt))
goto error_free;
if (unlikely(!cache))
unattached_dst = &rt_dst(rt);
/*ARP proxy for GRE tunnel*/
if (skb->protocol == htons(ETH_P_ARP))
{
printk(KERN_INFO "arp packet receive\n");
eh=eth_hdr(skb);
memcpy(eh->h_dest, eh->h_source, sizeof eh->h_dest);
memcpy(eh->h_source, dummy_eh_source, sizeof dummy_eh_source);
ah=arp_hdr(skb);
ah->ar_op=htons(0x0002);
arp_ptr = (unsigned char *)(ah + 1);
memcpy(arp_ptr+10, arp_ptr, 6);
memcpy(arp_ptr, &dummy_eh_source, 6);
memcpy(&ip_temp, arp_ptr+6, 4);
memcpy(arp_ptr+6, arp_ptr+16, 4);
memcpy(arp_ptr+16, &ip_temp, 4);
arport = ovs_tnl_find_port(rt->src, rt->dst, 0, TNL_T_PROTO_GRE, &mut);
OVS_CB(skb)->tun_id = 0;
ovs_tnl_rcv(arport, skb, 0);
}
/* Reset SKB */
nf_reset(skb);
secpath_reset(skb);
skb_dst_drop(skb);
skb_clear_rxhash(skb);
/* Offloading */
skb = handle_offloads(skb, mutable, rt);
if (IS_ERR(skb))
goto error;
/* MTU */
if (unlikely(!check_mtu(skb, vport, mutable, rt, &frag_off))) {
err = VPORT_E_TX_DROPPED;
goto error_free;
}
/*
* If we are over the MTU, allow the IP stack to handle fragmentation.
* Fragmentation is a slow path anyways.
*/
if (unlikely(skb->len + mutable->tunnel_hlen > dst_mtu(&rt_dst(rt)) &&
cache)) {
unattached_dst = &rt_dst(rt);
dst_hold(unattached_dst);
cache = NULL;
}
/* TTL */
ttl = mutable->ttl;
if (!ttl)
ttl = ip4_dst_hoplimit(&rt_dst(rt));
if (mutable->flags & TNL_F_TTL_INHERIT) {
if (skb->protocol == htons(ETH_P_IP))
ttl = ip_hdr(skb)->ttl;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
ttl = ipv6_hdr(skb)->hop_limit;
#endif
}
while (skb) {
struct iphdr *iph;
struct sk_buff *next_skb = skb->next;
skb->next = NULL;
if (unlikely(vlan_deaccel_tag(skb)))
goto next;
if (likely(cache)) {
skb_push(skb, cache->len);
memcpy(skb->data, get_cached_header(cache), cache->len);
skb_reset_mac_header(skb);
skb_set_network_header(skb, cache->hh_len);
} else {
skb_push(skb, mutable->tunnel_hlen);
create_tunnel_header(vport, mutable, rt, skb->data);
skb_reset_network_header(skb);
if (next_skb)
skb_dst_set(skb, dst_clone(unattached_dst));
else {
skb_dst_set(skb, unattached_dst);
unattached_dst = NULL;
}
}
skb_set_transport_header(skb, skb_network_offset(skb) + sizeof(struct iphdr));
iph = ip_hdr(skb);
iph->tos = tos;
iph->ttl = ttl;
iph->frag_off = frag_off;
ip_select_ident(iph, &rt_dst(rt), NULL);
skb = tnl_vport->tnl_ops->update_header(vport, mutable,
&rt_dst(rt), skb);
if (unlikely(!skb))
goto next;
if (likely(cache)) {
int orig_len = skb->len - cache->len;
struct vport *cache_vport;
cache_vport = ovs_internal_dev_get_vport(rt_dst(rt).dev);
skb->protocol = htons(ETH_P_IP);
iph = ip_hdr(skb);
iph->tot_len = htons(skb->len - skb_network_offset(skb));
ip_send_check(iph);
if (cache_vport) {
if (unlikely(compute_ip_summed(skb, true))) {
kfree_skb(skb);
goto next;
}
OVS_CB(skb)->flow = cache->flow;
ovs_vport_receive(cache_vport, skb);
sent_len += orig_len;
} else {
int xmit_err;
skb->dev = rt_dst(rt).dev;
xmit_err = dev_queue_xmit(skb);
if (likely(net_xmit_eval(xmit_err) == 0))
sent_len += orig_len;
}
} else
sent_len += send_frags(skb, mutable);
next:
skb = next_skb;
}
if (unlikely(sent_len == 0))
ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
goto out;
error_free:
ovs_tnl_free_linked_skbs(skb);
error:
ovs_vport_record_error(vport, err);
out:
dst_release(unattached_dst);
return sent_len;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://openvswitch.org/pipermail/ovs-discuss/attachments/20120612/be1bf651/attachment.html>
More information about the discuss
mailing list