diff options
| -rw-r--r-- | net/openvswitch/flow_netlink.c | 95 | 
1 files changed, 90 insertions, 5 deletions
| diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index dbdcaaa27f5b..7176156d3844 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2317,6 +2317,62 @@ static struct sw_flow_actions *nla_alloc_flow_actions(int size)  	return sfa;  } +static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len); + +static void ovs_nla_free_check_pkt_len_action(const struct nlattr *action) +{ +	const struct nlattr *a; +	int rem; + +	nla_for_each_nested(a, action, rem) { +		switch (nla_type(a)) { +		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL: +		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER: +			ovs_nla_free_nested_actions(nla_data(a), nla_len(a)); +			break; +		} +	} +} + +static void ovs_nla_free_clone_action(const struct nlattr *action) +{ +	const struct nlattr *a = nla_data(action); +	int rem = nla_len(action); + +	switch (nla_type(a)) { +	case OVS_CLONE_ATTR_EXEC: +		/* The real list of actions follows this attribute. */ +		a = nla_next(a, &rem); +		ovs_nla_free_nested_actions(a, rem); +		break; +	} +} + +static void ovs_nla_free_dec_ttl_action(const struct nlattr *action) +{ +	const struct nlattr *a = nla_data(action); + +	switch (nla_type(a)) { +	case OVS_DEC_TTL_ATTR_ACTION: +		ovs_nla_free_nested_actions(nla_data(a), nla_len(a)); +		break; +	} +} + +static void ovs_nla_free_sample_action(const struct nlattr *action) +{ +	const struct nlattr *a = nla_data(action); +	int rem = nla_len(action); + +	switch (nla_type(a)) { +	case OVS_SAMPLE_ATTR_ARG: +		/* The real list of actions follows this attribute. */ +		a = nla_next(a, &rem); +		ovs_nla_free_nested_actions(a, rem); +		break; +	} +} +  static void ovs_nla_free_set_action(const struct nlattr *a)  {  	const struct nlattr *ovs_key = nla_data(a); @@ -2330,25 +2386,54 @@ static void ovs_nla_free_set_action(const struct nlattr *a)  	}  } -void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) +static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)  {  	const struct nlattr *a;  	int rem; -	if (!sf_acts) +	/* Whenever new actions are added, the need to update this +	 * function should be considered. +	 */ +	BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 23); + +	if (!actions)  		return; -	nla_for_each_attr(a, sf_acts->actions, sf_acts->actions_len, rem) { +	nla_for_each_attr(a, actions, len, rem) {  		switch (nla_type(a)) { -		case OVS_ACTION_ATTR_SET: -			ovs_nla_free_set_action(a); +		case OVS_ACTION_ATTR_CHECK_PKT_LEN: +			ovs_nla_free_check_pkt_len_action(a); +			break; + +		case OVS_ACTION_ATTR_CLONE: +			ovs_nla_free_clone_action(a);  			break; +  		case OVS_ACTION_ATTR_CT:  			ovs_ct_free_action(a);  			break; + +		case OVS_ACTION_ATTR_DEC_TTL: +			ovs_nla_free_dec_ttl_action(a); +			break; + +		case OVS_ACTION_ATTR_SAMPLE: +			ovs_nla_free_sample_action(a); +			break; + +		case OVS_ACTION_ATTR_SET: +			ovs_nla_free_set_action(a); +			break;  		}  	} +} + +void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) +{ +	if (!sf_acts) +		return; +	ovs_nla_free_nested_actions(sf_acts->actions, sf_acts->actions_len);  	kfree(sf_acts);  } | 
