datapath/actions.c
/* Execute a list of actions against 'skb'. */
Execute a list of actions against 'skb'.
Execute a list of actions against ' skb ' .
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
			      struct sw_flow_key *key,
			      const struct nlattr *attr, int len)
{
	const struct nlattr *a;
	int rem;
	for (a = attr, rem = len; rem > 0;
	     a = nla_next(a, &rem)) {
		int err = 0;
		switch (nla_type(a)) {
		case OVS_ACTION_ATTR_OUTPUT: {
			int port = nla_get_u32(a);
			struct sk_buff *clone;
			if (nla_is_last(a, rem)) {
				do_output(dp, skb, port, key);
				return 0;
			}
			clone = skb_clone(skb, GFP_ATOMIC);
			if (clone)
				do_output(dp, clone, port, key);
			OVS_CB(skb)->cutlen = 0;
			break;
		}
		case OVS_ACTION_ATTR_TRUNC: {
			struct ovs_action_trunc *trunc = nla_data(a);
			if (skb->len > trunc->max_len)
				OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
			break;
		}
		case OVS_ACTION_ATTR_USERSPACE:
			output_userspace(dp, skb, key, a, attr,
						     len, OVS_CB(skb)->cutlen);
			OVS_CB(skb)->cutlen = 0;
			break;
		case OVS_ACTION_ATTR_HASH:
			execute_hash(skb, key, a);
			break;
		case OVS_ACTION_ATTR_PUSH_MPLS:
			err = push_mpls(skb, key, nla_data(a));
			break;
		case OVS_ACTION_ATTR_POP_MPLS:
			err = pop_mpls(skb, key, nla_get_be16(a));
			break;
		case OVS_ACTION_ATTR_PUSH_VLAN:
			err = push_vlan(skb, key, nla_data(a));
			break;
		case OVS_ACTION_ATTR_POP_VLAN:
			err = pop_vlan(skb, key);
			break;
		case OVS_ACTION_ATTR_RECIRC: {
			bool last = nla_is_last(a, rem);
			err = execute_recirc(dp, skb, key, a, last);
			if (last) {
				return err;
			}
			break;
		}
		case OVS_ACTION_ATTR_SET:
			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: {
			bool last = nla_is_last(a, rem);
			err = sample(dp, skb, key, a, last);
			if (last)
				return err;
			break;
		}
		case OVS_ACTION_ATTR_CT:
			if (!is_flow_key_valid(key)) {
				err = ovs_flow_key_update(skb, key);
				if (err)
					return err;
			}
			err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key,
					     nla_data(a));
			if (err)
				return err == -EINPROGRESS ? 0 : err;
			break;
		case OVS_ACTION_ATTR_CT_CLEAR:
			err = ovs_ct_clear(skb, key);
			break;
		case OVS_ACTION_ATTR_PUSH_ETH:
			err = push_eth(skb, key, nla_data(a));
			break;
		case OVS_ACTION_ATTR_POP_ETH:
			err = pop_eth(skb, key);
			break;
		case OVS_ACTION_ATTR_PUSH_NSH: {
			u8 buffer[NSH_HDR_MAX_LEN];
			struct nshhdr *nh = (struct nshhdr *)buffer;
			err = nsh_hdr_from_nlattr(nla_data(a), nh,
						  NSH_HDR_MAX_LEN);
			if (unlikely(err))
				break;
			err = push_nsh(skb, key, nh);
			break;
		}
		case OVS_ACTION_ATTR_POP_NSH:
			err = pop_nsh(skb, key);
			break;
		case OVS_ACTION_ATTR_METER:
			if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) {
				consume_skb(skb);
				return 0;
			}
                       break;
		case OVS_ACTION_ATTR_CLONE: {
			bool last = nla_is_last(a, rem);
			err = clone(dp, skb, key, a, last);
			if (last)
				return err;
			break;
		}
		case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
                        bool last = nla_is_last(a, rem);
                        err = execute_check_pkt_len(dp, skb, key, a, last);
                        if (last)
                                return err;
                        break;
                }
		}
		if (unlikely(err)) {
			kfree_skb(skb);
			return err;
		}
	}
	consume_skb(skb);
	return 0;
}
static int do_execute_actions ( struct datapath * dp , struct sk_buff * skb , struct sw_flow_key * key , const struct nlattr * attr , int len ) { const struct nlattr * a ; int rem ; for ( a = attr , rem = len ; rem > 0 ; a = nla_next ( a , & rem ) ) { int err = 0 ; switch ( nla_type ( a ) ) { case OVS_ACTION_ATTR_OUTPUT : { int port = nla_get_u32 ( a ) ; struct sk_buff * clone ; if ( nla_is_last ( a , rem ) ) { do_output ( dp , skb , port , key ) ; return 0 ; } clone = skb_clone ( skb , GFP_ATOMIC ) ; if ( clone ) do_output ( dp , clone , port , key ) ; OVS_CB ( skb ) -> cutlen = 0 ; break ; } case OVS_ACTION_ATTR_TRUNC : { struct ovs_action_trunc * trunc = nla_data ( a ) ; if ( skb -> len > trunc -> max_len ) OVS_CB ( skb ) -> cutlen = skb -> len - trunc -> max_len ; break ; } case OVS_ACTION_ATTR_USERSPACE : output_userspace ( dp , skb , key , a , attr , len , OVS_CB ( skb ) -> cutlen ) ; OVS_CB ( skb ) -> cutlen = 0 ; break ; case OVS_ACTION_ATTR_HASH : execute_hash ( skb , key , a ) ; break ; case OVS_ACTION_ATTR_PUSH_MPLS : err = push_mpls ( skb , key , nla_data ( a ) ) ; break ; case OVS_ACTION_ATTR_POP_MPLS : err = pop_mpls ( skb , key , nla_get_be16 ( a ) ) ; break ; case OVS_ACTION_ATTR_PUSH_VLAN : err = push_vlan ( skb , key , nla_data ( a ) ) ; break ; case OVS_ACTION_ATTR_POP_VLAN : err = pop_vlan ( skb , key ) ; break ; case OVS_ACTION_ATTR_RECIRC : { bool last = nla_is_last ( a , rem ) ; err = execute_recirc ( dp , skb , key , a , last ) ; if ( last ) { return err ; } break ; } case OVS_ACTION_ATTR_SET : 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 : { bool last = nla_is_last ( a , rem ) ; err = sample ( dp , skb , key , a , last ) ; if ( last ) return err ; break ; } case OVS_ACTION_ATTR_CT : if ( ! is_flow_key_valid ( key ) ) { err = ovs_flow_key_update ( skb , key ) ; if ( err ) return err ; } err = ovs_ct_execute ( ovs_dp_get_net ( dp ) , skb , key , nla_data ( a ) ) ; if ( err ) return err == - EINPROGRESS ? 0 : err ; break ; case OVS_ACTION_ATTR_CT_CLEAR : err = ovs_ct_clear ( skb , key ) ; break ; case OVS_ACTION_ATTR_PUSH_ETH : err = push_eth ( skb , key , nla_data ( a ) ) ; break ; case OVS_ACTION_ATTR_POP_ETH : err = pop_eth ( skb , key ) ; break ; case OVS_ACTION_ATTR_PUSH_NSH : { u8 buffer [ NSH_HDR_MAX_LEN ] ; struct nshhdr * nh = ( struct nshhdr * ) buffer ; err = nsh_hdr_from_nlattr ( nla_data ( a ) , nh , NSH_HDR_MAX_LEN ) ; if ( unlikely ( err ) ) break ; err = push_nsh ( skb , key , nh ) ; break ; } case OVS_ACTION_ATTR_POP_NSH : err = pop_nsh ( skb , key ) ; break ; case OVS_ACTION_ATTR_METER : if ( ovs_meter_execute ( dp , skb , key , nla_get_u32 ( a ) ) ) { consume_skb ( skb ) ; return 0 ; } break ; case OVS_ACTION_ATTR_CLONE : { bool last = nla_is_last ( a , rem ) ; err = clone ( dp , skb , key , a , last ) ; if ( last ) return err ; break ; } case OVS_ACTION_ATTR_CHECK_PKT_LEN : { bool last = nla_is_last ( a , rem ) ; err = execute_check_pkt_len ( dp , skb , key , a , last ) ; if ( last ) return err ; break ; } } if ( unlikely ( err ) ) { kfree_skb ( skb ) ; return err ; } } consume_skb ( skb ) ; return 0 ; }
Execute a list of actions against 'skb'.
Execute a list of actions against ' skb ' .
/* Every output action needs a separate clone
			 * of 'skb', In case the output action is the
			 * last action, cloning can be avoided.
			 */ /* 'skb' has been used for output.
				 */ /* If this is the last action, the skb has
				 * been consumed or freed.
				 * Return immediately.
				 */ /* Hide stolen IP fragments from user space. */