[ovs-dev] OVS Push VLAN Tag Hack and Problem

Naga Rohit, IIT Guwahati snagarohit at gmail.com
Wed May 23 05:14:45 UTC 2012


Hi,

I was working on a hack which can change the behavior of
"mod_vlan_vid" action and behave as "push_vlan" for a quick temporary
OF1.1 support. For this, I changed the following two functions:
(PS: I am using mininet framework)

FILE: ~/openvswitch/datapath/actions.c
FUNCTION:
static struct sk_buff *modify_vlan_tci(struct sk_buff *skb, __be16 tci)
{
	struct vlan_ethhdr *vh;
	__be16 old_tci;

	if (vlan_tx_tag_present(skb) || skb->protocol != htons(ETH_P_8021Q))
		return __vlan_hwaccel_put_tag(skb, ntohs(tci));

	skb = make_writable(skb, 0);
	if (unlikely(!skb))
		return NULL;

	if (unlikely(skb->len < VLAN_ETH_HLEN))
		return skb;

	vh = vlan_eth_hdr(skb);

	old_tci = vh->h_vlan_TCI;
	vh->h_vlan_TCI = tci;

	if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) {
		__be16 diff[] = { ~old_tci, vh->h_vlan_TCI };
		skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
	}

	return skb;
}
CHANGED TO:
static struct sk_buff *modify_vlan_tci(struct sk_buff *skb, __be16 tci)
{

	struct vlan_ethhdr *vh;
	__be16 old_tci;

	if (vlan_tx_tag_present(skb)) {
	        __be16 current_tag;
	        current_tag = vlan_tx_tag_get(skb);
	
	        skb = __vlan_put_tag(skb,current_tag);
	        return __vlan_hwaccel_put_tag(skb,ntohs(tci))
	}
	else if(skb->protocol != (ETH_P_8021Q)) {
	        return __vlan_hwaccel_put_tag(skb,ntohs(tci));
	}

	skb = make_writable(skb, 0);
	if (unlikely(!skb))
		return NULL;

	if (unlikely(skb->len < VLAN_ETH_HLEN))
		return skb;

	vh = vlan_eth_hdr(skb);

	old_tci = vh->h_vlan_TCI;
	vh->h_vlan_TCI = tci;

	if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) {
		__be16 diff[] = { ~old_tci, vh->h_vlan_TCI };
		skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
	}

	return skb;
}


FILE: ~/openvswitch/lib/dpif-netdev.c
FUNCTION:
static void
dp_netdev_set_dl_tci(struct ofpbuf *packet, uint16_t tci)
{
    struct vlan_eth_header *veh;
    struct eth_header *eh;

    eh = packet->l2;
    if (packet->size >= sizeof(struct vlan_eth_header)
        && eh->eth_type == htons(ETH_TYPE_VLAN)) {
        veh = packet->l2;
        veh->veth_tci = tci;
    } else {
        // Insert new 802.1Q header.
        struct vlan_eth_header tmp;
        memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
        memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
        tmp.veth_type = htons(ETH_TYPE_VLAN);
        tmp.veth_tci = tci;
        tmp.veth_next_type = eh->eth_type;

        veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
        memcpy(veh, &tmp, sizeof tmp);
        packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
    }
}
CHANGED TO:
static void
dp_netdev_set_dl_tci(struct ofpbuf *packet, uint16_t tci)
{

    struct vlan_eth_header *veh;
    struct eth_header *eh;

    eh = packet->l2;

        // Insert new 802.1Q header.
        struct vlan_eth_header tmp;
        memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
        memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
        tmp.veth_type = htons(ETH_TYPE_VLAN);
        tmp.veth_tci = tci;
        tmp.veth_next_type = eh->eth_type;

        veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
        memcpy(veh, &tmp, sizeof tmp);
        packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;

}


I have then followed the following steps:
make clean ; .//boot.sh ; configure ; make ; sudo make install ; sudo
cp ~/openvswitch/datapath/linux-2.6/openvswitch_mod.ko
/lib/modules/2.6.38-8-generic/kernel/drivers/net/openvswitch_mod.ko

and everything happens smoothly. But on running the mininet, with
specifying two "mod_vlan_vid" instructions in the action list, (flow
added using 'dpctl')  the final packet just seems to have the final
VLAN ID, as if my changes din't account to anything.

Where am I going wrong ? Does the changes I have made really result in
behavior that I intend to see ?

Thanking You,
Rohit



More information about the dev mailing list