X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Factions.c;h=30ea1d23e9c2ce99d7f6333ff35336ddf6a2de1d;hb=8e04c6e10c28e42c715eb9fef749554c123bddbc;hp=bc126a7f5a08953d51b3c3851b1ae2a0ca931565;hpb=85c9de194b9f432f7b8a66bda980cbab52a55b72;p=sliver-openvswitch.git diff --git a/datapath/actions.c b/datapath/actions.c index bc126a7f5..30ea1d23e 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2012 Nicira, Inc. + * Copyright (c) 2007-2013 Nicira, 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -31,8 +32,8 @@ #include #include #include +#include -#include "checksum.h" #include "datapath.h" #include "vlan.h" #include "vport.h" @@ -58,7 +59,7 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) if (unlikely(err)) return err; - if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) + if (skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_sub(skb->csum, csum_partial(skb->data + (2 * ETH_ALEN), VLAN_HLEN, 0)); @@ -100,7 +101,7 @@ static int pop_vlan(struct sk_buff *skb) if (unlikely(err)) return err; - __vlan_hwaccel_put_tag(skb, ntohs(tci)); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci)); return 0; } @@ -112,15 +113,15 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla /* push down current VLAN tag */ current_tag = vlan_tx_tag_get(skb); - if (!__vlan_put_tag(skb, current_tag)) + if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag)) return -ENOMEM; - if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) + if (skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_add(skb->csum, csum_partial(skb->data + (2 * ETH_ALEN), VLAN_HLEN, 0)); } - __vlan_hwaccel_put_tag(skb, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); + __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); return 0; } @@ -132,9 +133,13 @@ static int set_eth_addr(struct sk_buff *skb, if (unlikely(err)) return err; + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); + memcpy(eth_hdr(skb)->h_source, eth_key->eth_src, ETH_ALEN); memcpy(eth_hdr(skb)->h_dest, eth_key->eth_dst, ETH_ALEN); + ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); + return 0; } @@ -151,8 +156,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, if (likely(transport_len >= sizeof(struct udphdr))) { struct udphdr *uh = udp_hdr(skb); - if (uh->check || - get_ip_summed(skb) == OVS_CSUM_PARTIAL) { + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { inet_proto_csum_replace4(&uh->check, skb, *addr, new_addr, 1); if (!uh->check) @@ -179,8 +183,7 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, if (likely(transport_len >= sizeof(struct udphdr))) { struct udphdr *uh = udp_hdr(skb); - if (uh->check || - get_ip_summed(skb) == OVS_CSUM_PARTIAL) { + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { inet_proto_csum_replace16(&uh->check, skb, addr, new_addr, 1); if (!uh->check) @@ -301,7 +304,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) { struct udphdr *uh = udp_hdr(skb); - if (uh->check && get_ip_summed(skb) != OVS_CSUM_PARTIAL) { + if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) { set_tp_port(skb, port, new_port, &uh->check); if (!uh->check) @@ -352,6 +355,39 @@ static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key) return 0; } +static int set_sctp(struct sk_buff *skb, + const struct ovs_key_sctp *sctp_port_key) +{ + struct sctphdr *sh; + int err; + unsigned int sctphoff = skb_transport_offset(skb); + + err = make_writable(skb, sctphoff + sizeof(struct sctphdr)); + if (unlikely(err)) + return err; + + sh = sctp_hdr(skb); + if (sctp_port_key->sctp_src != sh->source || + sctp_port_key->sctp_dst != sh->dest) { + __le32 old_correct_csum, new_csum, old_csum; + + old_csum = sh->checksum; + old_correct_csum = sctp_compute_cksum(skb, sctphoff); + + sh->source = sctp_port_key->sctp_src; + sh->dest = sctp_port_key->sctp_dst; + + new_csum = sctp_compute_cksum(skb, sctphoff); + + /* Carry any checksum errors through. */ + sh->checksum = old_csum ^ old_correct_csum ^ new_csum; + + skb_clear_rxhash(skb); + } + + return 0; +} + static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port) { struct vport *vport; @@ -376,8 +412,10 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, const struct nlattr *a; int rem; + BUG_ON(!OVS_CB(skb)->pkt_key); + upcall.cmd = OVS_PACKET_CMD_ACTION; - upcall.key = &OVS_CB(skb)->flow->key; + upcall.key = OVS_CB(skb)->pkt_key; upcall.userdata = NULL; upcall.portid = 0; @@ -433,7 +471,7 @@ static int execute_set_action(struct sk_buff *skb, break; case OVS_KEY_ATTR_SKB_MARK: - skb_set_mark(skb, nla_get_u32(nested_attr)); + skb->mark = nla_get_u32(nested_attr); break; case OVS_KEY_ATTR_IPV4_TUNNEL: @@ -459,6 +497,10 @@ static int execute_set_action(struct sk_buff *skb, case OVS_KEY_ATTR_UDP: err = set_udp(skb, nla_data(nested_attr)); break; + + case OVS_KEY_ATTR_SCTP: + err = set_sctp(skb, nla_data(nested_attr)); + break; } return err; @@ -532,7 +574,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, /* We limit the number of times that we pass into execute_actions() * to avoid blowing out the stack in the event that we have a loop. */ -#define MAX_LOOPS 5 +#define MAX_LOOPS 4 struct loop_counter { u8 count; /* Count. */