@ -185,10 +185,15 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
return 0 ;
}
static int set_mpls ( struct sk_buff * skb , struct sw_flow_key * key ,
const __be32 * mpls_lse )
/* 'KEY' must not have any bits set outside of the 'MASK' */
# define MASKED(OLD, KEY, MASK) ((KEY) | ((OLD) & ~(MASK)))
# define SET_MASKED(OLD, KEY, MASK) ((OLD) = MASKED(OLD, KEY, MASK))
static int set_mpls ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const __be32 * mpls_lse , const __be32 * mask )
{
__be32 * stack ;
__be32 lse ;
int err ;
err = skb_ensure_writable ( skb , skb - > mac_len + MPLS_HLEN ) ;
@ -196,14 +201,16 @@ static int set_mpls(struct sk_buff *skb, struct sw_flow_key *key,
return err ;
stack = ( __be32 * ) skb_mpls_header ( skb ) ;
lse = MASKED ( * stack , * mpls_lse , * mask ) ;
if ( skb - > ip_summed = = CHECKSUM_COMPLETE ) {
__be32 diff [ ] = { ~ ( * stack ) , * mpls_lse } ;
__be32 diff [ ] = { ~ ( * stack ) , lse } ;
skb - > csum = ~ csum_partial ( ( char * ) diff , sizeof ( diff ) ,
~ skb - > csum ) ;
}
* stack = * mpls_ lse;
key - > mpls . top_lse = * mpls_ lse;
* stack = lse ;
flow_ key- > mpls . top_lse = lse ;
return 0 ;
}
@ -230,23 +237,39 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
ntohs ( vlan - > vlan_tci ) & ~ VLAN_TAG_PRESENT ) ;
}
static int set_eth_addr ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_ethernet * eth_key )
/* 'src' is already properly masked. */
static void ether_addr_copy_masked ( u8 * dst_ , const u8 * src_ , const u8 * mask_ )
{
u16 * dst = ( u16 * ) dst_ ;
const u16 * src = ( const u16 * ) src_ ;
const u16 * mask = ( const u16 * ) mask_ ;
SET_MASKED ( dst [ 0 ] , src [ 0 ] , mask [ 0 ] ) ;
SET_MASKED ( dst [ 1 ] , src [ 1 ] , mask [ 1 ] ) ;
SET_MASKED ( dst [ 2 ] , src [ 2 ] , mask [ 2 ] ) ;
}
static int set_eth_addr ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_ethernet * key ,
const struct ovs_key_ethernet * mask )
{
int err ;
err = skb_ensure_writable ( skb , ETH_HLEN ) ;
if ( unlikely ( err ) )
return err ;
skb_postpull_rcsum ( skb , eth_hdr ( skb ) , ETH_ALEN * 2 ) ;
ether_addr_copy ( eth_hdr ( skb ) - > h_source , eth_key - > eth_src ) ;
ether_addr_copy ( eth_hdr ( skb ) - > h_dest , eth_key - > eth_dst ) ;
ether_addr_copy_masked ( eth_hdr ( skb ) - > h_source , key - > eth_src ,
mask - > eth_src ) ;
ether_addr_copy_masked ( eth_hdr ( skb ) - > h_dest , key - > eth_dst ,
mask - > eth_dst ) ;
ovs_skb_postpush_rcsum ( skb , eth_hdr ( skb ) , ETH_ALEN * 2 ) ;
ether_addr_copy ( key - > eth . src , eth_key - > et h_src) ;
ether_addr_copy ( key - > eth . dst , eth_key - > et h_dst) ;
ether_addr_copy ( flow_ key- > eth . src , eth_hdr ( skb ) - > h_sou rce ) ;
ether_addr_copy ( flow_ key- > eth . dst , eth_hdr ( skb ) - > h_de st ) ;
return 0 ;
}
@ -304,6 +327,15 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
}
}
static void mask_ipv6_addr ( const __be32 old [ 4 ] , const __be32 addr [ 4 ] ,
const __be32 mask [ 4 ] , __be32 masked [ 4 ] )
{
masked [ 0 ] = MASKED ( old [ 0 ] , addr [ 0 ] , mask [ 0 ] ) ;
masked [ 1 ] = MASKED ( old [ 1 ] , addr [ 1 ] , mask [ 1 ] ) ;
masked [ 2 ] = MASKED ( old [ 2 ] , addr [ 2 ] , mask [ 2 ] ) ;
masked [ 3 ] = MASKED ( old [ 3 ] , addr [ 3 ] , mask [ 3 ] ) ;
}
static void set_ipv6_addr ( struct sk_buff * skb , u8 l4_proto ,
__be32 addr [ 4 ] , const __be32 new_addr [ 4 ] ,
bool recalculate_csum )
@ -315,29 +347,29 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
memcpy ( addr , new_addr , sizeof ( __be32 [ 4 ] ) ) ;
}
static void set_ipv6_tc ( struct ipv6hdr * nh , u8 tc )
static void set_ipv6_fl ( struct ipv6hdr * nh , u32 fl , u32 mask )
{
nh - > priority = tc > > 4 ;
nh - > flow_lbl [ 0 ] = ( nh - > flow_lbl [ 0 ] & 0x0F ) | ( ( tc & 0x0F ) < < 4 ) ;
/* Bits 21-24 are always unmasked, so this retains their values. */
SET_MASKED ( nh - > flow_lbl [ 0 ] , ( u8 ) ( fl > > 16 ) , ( u8 ) ( mask > > 16 ) ) ;
SET_MASKED ( nh - > flow_lbl [ 1 ] , ( u8 ) ( fl > > 8 ) , ( u8 ) ( mask > > 8 ) ) ;
SET_MASKED ( nh - > flow_lbl [ 2 ] , ( u8 ) fl , ( u8 ) mask ) ;
}
static void set_ipv6_fl ( struct ipv6hdr * nh , u32 fl )
static void set_ip_ttl ( struct sk_buff * skb , struct iphdr * nh , u8 new_ttl ,
u8 mask )
{
nh - > flow_lbl [ 0 ] = ( nh - > flow_lbl [ 0 ] & 0xF0 ) | ( fl & 0x000F0000 ) > > 16 ;
nh - > flow_lbl [ 1 ] = ( fl & 0x0000FF00 ) > > 8 ;
nh - > flow_lbl [ 2 ] = fl & 0x000000FF ;
}
new_ttl = MASKED ( nh - > ttl , new_ttl , mask ) ;
static void set_ip_ttl ( struct sk_buff * skb , struct iphdr * nh , u8 new_ttl )
{
csum_replace2 ( & nh - > check , htons ( nh - > ttl < < 8 ) , htons ( new_ttl < < 8 ) ) ;
nh - > ttl = new_ttl ;
}
static int set_ipv4 ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_ipv4 * ipv4_key )
static int set_ipv4 ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_ipv4 * key ,
const struct ovs_key_ipv4 * mask )
{
struct iphdr * nh ;
__be32 new_addr ;
int err ;
err = skb_ensure_writable ( skb , skb_network_offset ( skb ) +
@ -347,36 +379,49 @@ static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *key,
nh = ip_hdr ( skb ) ;
if ( ipv4_key - > ipv4_src ! = nh - > saddr ) {
set_ip_addr ( skb , nh , & nh - > saddr , ipv4_key - > ipv4_src ) ;
key - > ipv4 . addr . src = ipv4_key - > ipv4_src ;
}
/* Setting an IP addresses is typically only a side effect of
* matching on them in the current userspace implementation , so it
* makes sense to check if the value actually changed .
*/
if ( mask - > ipv4_src ) {
new_addr = MASKED ( nh - > saddr , key - > ipv4_src , mask - > ipv4_src ) ;
if ( ipv4_key - > ipv4_dst ! = nh - > daddr ) {
set_ip_addr ( skb , nh , & nh - > daddr , ipv4_key - > ipv4_dst ) ;
key - > ipv4 . addr . dst = ipv4_key - > ipv4_dst ;
if ( unlikely ( new_addr ! = nh - > saddr ) ) {
set_ip_addr ( skb , nh , & nh - > saddr , new_addr ) ;
flow_key - > ipv4 . addr . src = new_addr ;
}
}
if ( mask - > ipv4_dst ) {
new_addr = MASKED ( nh - > daddr , key - > ipv4_dst , mask - > ipv4_dst ) ;
if ( ipv4_key - > ipv4_tos ! = nh - > tos ) {
ipv4_change_dsfield ( nh , 0 , ipv4_key - > ipv4_tos ) ;
key - > ip . tos = nh - > tos ;
if ( unlikely ( new_addr ! = nh - > daddr ) ) {
set_ip_addr ( skb , nh , & nh - > daddr , new_addr ) ;
flow_key - > ipv4 . addr . dst = new_addr ;
}
}
if ( ipv4_key - > ipv4_ttl ! = nh - > ttl ) {
set_ip_ttl ( skb , nh , ipv4_key - > ipv4_ttl ) ;
key - > ip . ttl = ipv4_key - > ipv4_ttl ;
if ( mask - > ipv4_tos ) {
ipv4_change_dsfield ( nh , ~ mask - > ipv4_tos , key - > ipv4_tos ) ;
flow_key - > ip . tos = nh - > tos ;
}
if ( mask - > ipv4_ttl ) {
set_ip_ttl ( skb , nh , key - > ipv4_ttl , mask - > ipv4_ttl ) ;
flow_key - > ip . ttl = nh - > ttl ;
}
return 0 ;
}
static int set_ipv6 ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_ipv6 * ipv6_key )
static bool is_ipv6_mask_nonzero ( const __be32 addr [ 4 ] )
{
return ! ! ( addr [ 0 ] | addr [ 1 ] | addr [ 2 ] | addr [ 3 ] ) ;
}
static int set_ipv6 ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_ipv6 * key ,
const struct ovs_key_ipv6 * mask )
{
struct ipv6hdr * nh ;
int err ;
__be32 * saddr ;
__be32 * daddr ;
err = skb_ensure_writable ( skb , skb_network_offset ( skb ) +
sizeof ( struct ipv6hdr ) ) ;
@ -384,71 +429,77 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *key,
return err ;
nh = ipv6_hdr ( skb ) ;
saddr = ( __be32 * ) & nh - > saddr ;
daddr = ( __be32 * ) & nh - > daddr ;
if ( memcmp ( ipv6_key - > ipv6_src , saddr , sizeof ( ipv6_key - > ipv6_src ) ) ) {
set_ipv6_addr ( skb , ipv6_key - > ipv6_proto , saddr ,
ipv6_key - > ipv6_src , true ) ;
memcpy ( & key - > ipv6 . addr . src , ipv6_key - > ipv6_src ,
sizeof ( ipv6_key - > ipv6_src ) ) ;
}
if ( memcmp ( ipv6_key - > ipv6_dst , daddr , sizeof ( ipv6_key - > ipv6_dst ) ) ) {
/* Setting an IP addresses is typically only a side effect of
* matching on them in the current userspace implementation , so it
* makes sense to check if the value actually changed .
*/
if ( is_ipv6_mask_nonzero ( mask - > ipv6_src ) ) {
__be32 * saddr = ( __be32 * ) & nh - > saddr ;
__be32 masked [ 4 ] ;
mask_ipv6_addr ( saddr , key - > ipv6_src , mask - > ipv6_src , masked ) ;
if ( unlikely ( memcmp ( saddr , masked , sizeof ( masked ) ) ) ) {
set_ipv6_addr ( skb , key - > ipv6_proto , saddr , masked ,
true ) ;
memcpy ( & flow_key - > ipv6 . addr . src , masked ,
sizeof ( flow_key - > ipv6 . addr . src ) ) ;
}
}
if ( is_ipv6_mask_nonzero ( mask - > ipv6_dst ) ) {
unsigned int offset = 0 ;
int flags = IP6_FH_F_SKIP_RH ;
bool recalc_csum = true ;
if ( ipv6_ext_hdr ( nh - > nexthdr ) )
recalc_csum = ipv6_find_hdr ( skb , & offset ,
NEXTHDR_ROUTING , NULL ,
& flags ) ! = NEXTHDR_ROUTING ;
set_ipv6_addr ( skb , ipv6_key - > ipv6_proto , daddr ,
ipv6_key - > ipv6_dst , recalc_csum ) ;
memcpy ( & key - > ipv6 . addr . dst , ipv6_key - > ipv6_dst ,
sizeof ( ipv6_key - > ipv6_dst ) ) ;
__be32 * daddr = ( __be32 * ) & nh - > daddr ;
__be32 masked [ 4 ] ;
mask_ipv6_addr ( daddr , key - > ipv6_dst , mask - > ipv6_dst , masked ) ;
if ( unlikely ( memcmp ( daddr , masked , sizeof ( masked ) ) ) ) {
if ( ipv6_ext_hdr ( nh - > nexthdr ) )
recalc_csum = ( ipv6_find_hdr ( skb , & offset ,
NEXTHDR_ROUTING ,
NULL , & flags )
! = NEXTHDR_ROUTING ) ;
set_ipv6_addr ( skb , key - > ipv6_proto , daddr , masked ,
recalc_csum ) ;
memcpy ( & flow_key - > ipv6 . addr . dst , masked ,
sizeof ( flow_key - > ipv6 . addr . dst ) ) ;
}
}
if ( mask - > ipv6_tclass ) {
ipv6_change_dsfield ( nh , ~ mask - > ipv6_tclass , key - > ipv6_tclass ) ;
flow_key - > ip . tos = ipv6_get_dsfield ( nh ) ;
}
if ( mask - > ipv6_label ) {
set_ipv6_fl ( nh , ntohl ( key - > ipv6_label ) ,
ntohl ( mask - > ipv6_label ) ) ;
flow_key - > ipv6 . label =
* ( __be32 * ) nh & htonl ( IPV6_FLOWINFO_FLOWLABEL ) ;
}
if ( mask - > ipv6_hlimit ) {
SET_MASKED ( nh - > hop_limit , key - > ipv6_hlimit , mask - > ipv6_hlimit ) ;
flow_key - > ip . ttl = nh - > hop_limit ;
}
set_ipv6_tc ( nh , ipv6_key - > ipv6_tclass ) ;
key - > ip . tos = ipv6_get_dsfield ( nh ) ;
set_ipv6_fl ( nh , ntohl ( ipv6_key - > ipv6_label ) ) ;
key - > ipv6 . label = * ( __be32 * ) nh & htonl ( IPV6_FLOWINFO_FLOWLABEL ) ;
nh - > hop_limit = ipv6_key - > ipv6_hlimit ;
key - > ip . ttl = ipv6_key - > ipv6_hlimit ;
return 0 ;
}
/* Must follow skb_ensure_writable() since that can move the skb data. */
static void set_tp_port ( struct sk_buff * skb , __be16 * port ,
__be16 new_port , __sum16 * check )
__be16 new_port , __sum16 * check )
{
inet_proto_csum_replace2 ( check , skb , * port , new_port , 0 ) ;
* port = new_port ;
skb_clear_hash ( skb ) ;
}
static void set_udp_port ( struct sk_buff * skb , __be16 * port , __be16 new_port )
{
struct udphdr * uh = udp_hdr ( skb ) ;
if ( uh - > check & & skb - > ip_summed ! = CHECKSUM_PARTIAL ) {
set_tp_port ( skb , port , new_port , & uh - > check ) ;
if ( ! uh - > check )
uh - > check = CSUM_MANGLED_0 ;
} else {
* port = new_port ;
skb_clear_hash ( skb ) ;
}
}
static int set_udp ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_udp * udp_port_key )
static int set_udp ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_udp * key ,
const struct ovs_key_udp * mask )
{
struct udphdr * uh ;
__be16 src , dst ;
int err ;
err = skb_ensure_writable ( skb , skb_transport_offset ( skb ) +
@ -457,23 +508,40 @@ static int set_udp(struct sk_buff *skb, struct sw_flow_key *key,
return err ;
uh = udp_hdr ( skb ) ;
if ( udp_port_key - > udp_src ! = uh - > source ) {
set_udp_port ( skb , & uh - > source , udp_port_key - > udp_src ) ;
key - > tp . src = udp_port_key - > udp_src ;
}
/* Either of the masks is non-zero, so do not bother checking them. */
src = MASKED ( uh - > source , key - > udp_src , mask - > udp_src ) ;
dst = MASKED ( uh - > dest , key - > udp_dst , mask - > udp_dst ) ;
if ( udp_port_key - > udp_dst ! = uh - > dest ) {
set_udp_port ( skb , & uh - > dest , udp_port_key - > udp_dst ) ;
key - > tp . dst = udp_port_key - > udp_dst ;
if ( uh - > check & & skb - > ip_summed ! = CHECKSUM_PARTIAL ) {
if ( likely ( src ! = uh - > source ) ) {
set_tp_port ( skb , & uh - > source , src , & uh - > check ) ;
flow_key - > tp . src = src ;
}
if ( likely ( dst ! = uh - > dest ) ) {
set_tp_port ( skb , & uh - > dest , dst , & uh - > check ) ;
flow_key - > tp . dst = dst ;
}
if ( unlikely ( ! uh - > check ) )
uh - > check = CSUM_MANGLED_0 ;
} else {
uh - > source = src ;
uh - > dest = dst ;
flow_key - > tp . src = src ;
flow_key - > tp . dst = dst ;
}
skb_clear_hash ( skb ) ;
return 0 ;
}
static int set_tcp ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_tcp * tcp_port_key )
static int set_tcp ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_tcp * key ,
const struct ovs_key_tcp * mask )
{
struct tcphdr * th ;
__be16 src , dst ;
int err ;
err = skb_ensure_writable ( skb , skb_transport_offset ( skb ) +
@ -482,50 +550,49 @@ static int set_tcp(struct sk_buff *skb, struct sw_flow_key *key,
return err ;
th = tcp_hdr ( skb ) ;
if ( tcp_port_key - > tcp_src ! = th - > source ) {
set_tp_port ( skb , & th - > source , tcp_port_key - > tcp_src , & th - > check ) ;
key - > tp . src = tcp_port_key - > tcp_src ;
src = MASKED ( th - > source , key - > tcp_src , mask - > tcp_src ) ;
if ( likely ( src ! = th - > source ) ) {
set_tp_port ( skb , & th - > source , src , & th - > check ) ;
flow_key - > tp . src = src ;
}
if ( tcp_port_key - > tcp_ dst ! = th - > dest ) {
set_tp_port ( skb , & th - > dest , tcp_port_key - > tcp_ dst, & th - > check ) ;
key - > tp . dst = tcp_port_key - > tcp_ dst;
dst = MASKED ( th - > dest , key - > tcp_dst , mask - > tcp_dst ) ;
if ( likely ( dst ! = th - > dest ) ) {
set_tp_port ( skb , & th - > dest , dst , & th - > check ) ;
flow_ key- > tp . dst = dst ;
}
skb_clear_hash ( skb ) ;
return 0 ;
}
static int set_sctp ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct ovs_key_sctp * sctp_port_key )
static int set_sctp ( struct sk_buff * skb , struct sw_flow_key * flow_key ,
const struct ovs_key_sctp * key ,
const struct ovs_key_sctp * mask )
{
unsigned int sctphoff = skb_transport_offset ( skb ) ;
struct sctphdr * sh ;
__le32 old_correct_csum , new_csum , old_csum ;
int err ;
unsigned int sctphoff = skb_transport_offset ( skb ) ;
err = skb_ensure_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 ) ;
old_csum = sh - > checksum ;
old_correct_csum = sctp_compute_cksum ( skb , sctphoff ) ;
sh - > source = MASKED ( sh - > source , key - > sctp_src , mask - > sctp_src ) ;
sh - > dest = MASKED ( sh - > dest , key - > sctp_dst , mask - > sctp_dst ) ;
sh - > source = sctp_port_key - > sctp_src ;
sh - > dest = sctp_port_key - > sctp_dst ;
new_csum = sctp_compute_cksum ( skb , sctphoff ) ;
new_csum = sctp_compute_cksum ( skb , sctphoff ) ;
/* Carry any checksum errors through. */
sh - > checksum = old_csum ^ old_correct_csum ^ new_csum ;
/* Carry any checksum errors through. */
sh - > checksum = old_csum ^ old_correct_csum ^ new_csum ;
skb_clear_hash ( skb ) ;
key - > tp . src = sctp_port_key - > sctp_src ;
key - > tp . dst = sctp_port_key - > sctp_dst ;
}
skb_clear_hash ( skb ) ;
flow_key - > tp . src = sh - > source ;
flow_key - > tp . dst = sh - > dest ;
return 0 ;
}
@ -653,52 +720,77 @@ static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key,
key - > ovs_flow_hash = hash ;
}
static int execute_set_action ( struct sk_buff * skb , struct sw_flow_key * key ,
const struct nlattr * nested_attr )
static int execute_set_action ( struct sk_buff * skb ,
struct sw_flow_key * flow_key ,
const struct nlattr * a )
{
/* Only tunnel set execution is supported without a mask. */
if ( nla_type ( a ) = = OVS_KEY_ATTR_TUNNEL_INFO ) {
OVS_CB ( skb ) - > egress_tun_info = nla_data ( a ) ;
return 0 ;
}
return - EINVAL ;
}
/* Mask is at the midpoint of the data. */
# define get_mask(a, type) ((const type)nla_data(a) + 1)
static int execute_masked_set_action ( struct sk_buff * skb ,
struct sw_flow_key * flow_key ,
const struct nlattr * a )
{
int err = 0 ;
switch ( nla_type ( nested_attr ) ) {
switch ( nla_type ( a ) ) {
case OVS_KEY_ATTR_PRIORITY :
skb - > priority = nla_get_u32 ( nested_attr ) ;
key - > phy . priority = skb - > priority ;
SET_MASKED ( skb - > priority , nla_get_u32 ( a ) , * get_mask ( a , u32 * ) ) ;
flow_ key- > phy . priority = skb - > priority ;
break ;
case OVS_KEY_ATTR_SKB_MARK :
skb - > mark = nla_get_u32 ( nested_attr ) ;
key - > phy . skb_mark = skb - > mark ;
SET_MASKED ( skb - > mark , nla_get_u32 ( a ) , * get_mask ( a , u32 * ) ) ;
flow_ key- > phy . skb_mark = skb - > mark ;
break ;
case OVS_KEY_ATTR_TUNNEL_INFO :
OVS_CB ( skb ) - > egress_tun_info = nla_data ( nested_attr ) ;
/* Masked data not supported for tunnel. */
err = - EINVAL ;
break ;
case OVS_KEY_ATTR_ETHERNET :
err = set_eth_addr ( skb , key , nla_data ( nested_attr ) ) ;
err = set_eth_addr ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_ethernet * ) ) ;
break ;
case OVS_KEY_ATTR_IPV4 :
err = set_ipv4 ( skb , key , nla_data ( nested_attr ) ) ;
err = set_ipv4 ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_ipv4 * ) ) ;
break ;
case OVS_KEY_ATTR_IPV6 :
err = set_ipv6 ( skb , key , nla_data ( nested_attr ) ) ;
err = set_ipv6 ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_ipv6 * ) ) ;
break ;
case OVS_KEY_ATTR_TCP :
err = set_tcp ( skb , key , nla_data ( nested_attr ) ) ;
err = set_tcp ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_tcp * ) ) ;
break ;
case OVS_KEY_ATTR_UDP :
err = set_udp ( skb , key , nla_data ( nested_attr ) ) ;
err = set_udp ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_udp * ) ) ;
break ;
case OVS_KEY_ATTR_SCTP :
err = set_sctp ( skb , key , nla_data ( nested_attr ) ) ;
err = set_sctp ( skb , flow_key , nla_data ( a ) ,
get_mask ( a , struct ovs_key_sctp * ) ) ;
break ;
case OVS_KEY_ATTR_MPLS :
err = set_mpls ( skb , key , nla_data ( nested_attr ) ) ;
err = set_mpls ( skb , flow_key , nla_data ( a ) , get_mask ( a ,
__be32 * ) ) ;
break ;
}
@ -818,6 +910,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
err = execute_set_action ( skb , key , nla_data ( a ) ) ;
break ;
case OVS_ACTION_ATTR_SET_MASKED :
case OVS_ACTION_ATTR_SET_TO_MASKED :
err = execute_masked_set_action ( skb , key , nla_data ( a ) ) ;
break ;
case OVS_ACTION_ATTR_SAMPLE :
err = sample ( dp , skb , key , a ) ;
break ;