switch (action) { case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_TRUNC: case OVS_ACTION_ATTR_USERSPACE: case OVS_ACTION_ATTR_DROP: case OVS_ACTION_ATTR_PSAMPLE: break;
case OVS_ACTION_ATTR_CT: case OVS_ACTION_ATTR_CT_CLEAR: case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_PUSH_NSH: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_SET: case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_CHECK_PKT_LEN: case OVS_ACTION_ATTR_ADD_MPLS: case OVS_ACTION_ATTR_DEC_TTL: default: returntrue;
}
} returnfalse;
}
if (match->key->tp.src ==
htons(NDISC_NEIGHBOUR_SOLICITATION) ||
match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
key_expected |= 1 << OVS_KEY_ATTR_ND; /* Original direction conntrack tuple * uses the same space as the ND fields * in the key, so both are not allowed * at the same time.
*/
mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6); if (match->mask && (match->mask->key.tp.src == htons(0xff)))
mask_allowed |= 1 << OVS_KEY_ATTR_ND;
}
}
}
}
size_t ovs_tun_key_attr_size(void)
{ /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider * updating this function.
*/ return nla_total_size_64bit(8) /* OVS_TUNNEL_KEY_ATTR_ID */
+ nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */
+ nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */ /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
*/
+ nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
}
static size_t ovs_nsh_key_attr_size(void)
{ /* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider * updating this function.
*/ return nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */ /* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are * mutually exclusive, so the bigger one can cover * the small one.
*/
+ nla_total_size(NSH_CTX_HDRS_MAX_LEN);
}
size_t ovs_key_attr_size(void)
{ /* Whenever adding new OVS_KEY_ FIELDS, we should consider * updating this function.
*/
BUILD_BUG_ON(OVS_KEY_ATTR_MAX != 32);
attrs = *attrsp;
nla_for_each_nested(nla, attr, rem) {
u16 type = nla_type(nla); int expected_len;
if (type > OVS_KEY_ATTR_MAX) {
OVS_NLERR(log, "Key type %d is out of range max %d",
type, OVS_KEY_ATTR_MAX); return -EINVAL;
}
if (type == OVS_KEY_ATTR_PACKET_TYPE ||
type == OVS_KEY_ATTR_ND_EXTENSIONS ||
type == OVS_KEY_ATTR_TUNNEL_INFO) {
OVS_NLERR(log, "Key type %d is not supported", type); return -EINVAL;
}
if (nla_len(a) > sizeof(match->key->tun_opts)) {
OVS_NLERR(log, "Geneve option length err (len %d, max %zu).",
nla_len(a), sizeof(match->key->tun_opts)); return -EINVAL;
}
if (nla_len(a) % 4 != 0) {
OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.",
nla_len(a)); return -EINVAL;
}
/* We need to record the length of the options passed * down, otherwise packets with the same format but * additional options will be silently matched.
*/ if (!is_mask) {
SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a), false);
} else { /* This is somewhat unusual because it looks at * both the key and mask while parsing the * attributes (and by extension assumes the key * is parsed first). Normally, we would verify * that each is the correct length and that the * attributes line up in the validate function. * However, that is difficult because this is * variable length and we won't have the * information later.
*/ if (match->key->tun_opts_len != nla_len(a)) {
OVS_NLERR(log, "Geneve option len %d != mask len %d",
match->key->tun_opts_len, nla_len(a)); return -EINVAL;
}
if (!(key_attrs & (1 << OVS_KEY_ATTR_ENCAP))) { /* Not a VLAN. */ return 0;
}
if ((!inner && !encap_valid) || (inner && !i_encap_valid)) {
OVS_NLERR(log, "Encap mask attribute is set for non-%s frame.",
(inner) ? "C-VLAN" : "VLAN"); return -EINVAL;
}
if (a[OVS_KEY_ATTR_VLAN])
tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
if (a[OVS_KEY_ATTR_ETHERTYPE])
tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
if (tpid != htons(0xffff)) {
OVS_NLERR(log, "Must have an exact match on %s TPID (mask=%x).",
(inner) ? "C-VLAN" : "VLAN", ntohs(tpid)); return -EINVAL;
} if (!(tci & htons(VLAN_CFI_MASK))) {
OVS_NLERR(log, "%s TCI mask does not have exact match for VLAN_CFI_MASK bit.",
(inner) ? "C-VLAN" : "VLAN"); return -EINVAL;
}
/* For layer 3 packets the Ethernet type is provided * and treated as metadata but no MAC addresses are provided.
*/ if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
(*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)))
mac_proto = MAC_PROTO_NONE;
has_md1 = true; for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++)
SW_FLOW_KEY_PUT(match, nsh.context[i],
md1->context[i], is_mask); break;
} case OVS_NSH_KEY_ATTR_MD2: if (!is_push_nsh) /* Not supported MD type 2 yet */ return -ENOTSUPP;
if (attrs & (1 << OVS_KEY_ATTR_VLAN)) { /* VLAN attribute is always parsed before getting here since it * may occur multiple times.
*/
OVS_NLERR(log, "VLAN attribute unexpected."); return -EINVAL;
}
if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask,
log); if (err) return err;
} elseif (!is_mask) {
SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
}
} elseif (!match->key->eth.type) {
OVS_NLERR(log, "Either Ethernet header or EtherType is required."); return -EINVAL;
}
if (attrs & (1 << OVS_KEY_ATTR_IPV4)) { conststruct ovs_key_ipv4 *ipv4_key;
ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
OVS_NLERR(log, "IPv4 frag type %d is out of range max %d",
ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX); return -EINVAL;
}
SW_FLOW_KEY_PUT(match, ip.proto,
ipv4_key->ipv4_proto, is_mask);
SW_FLOW_KEY_PUT(match, ip.tos,
ipv4_key->ipv4_tos, is_mask);
SW_FLOW_KEY_PUT(match, ip.ttl,
ipv4_key->ipv4_ttl, is_mask);
SW_FLOW_KEY_PUT(match, ip.frag,
ipv4_key->ipv4_frag, is_mask);
SW_FLOW_KEY_PUT(match, ipv4.addr.src,
ipv4_key->ipv4_src, is_mask);
SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
ipv4_key->ipv4_dst, is_mask);
attrs &= ~(1 << OVS_KEY_ATTR_IPV4);
}
if (attrs & (1 << OVS_KEY_ATTR_IPV6)) { conststruct ovs_key_ipv6 *ipv6_key;
ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
OVS_NLERR(log, "IPv6 frag type %d is out of range max %d",
ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX); return -EINVAL;
}
if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
OVS_NLERR(log, "IPv6 flow label %x is out of range (max=%x)",
ntohl(ipv6_key->ipv6_label), (1 << 20) - 1); return -EINVAL;
}
/** * ovs_nla_get_match - parses Netlink attributes into a flow key and * mask. In case the 'mask' is NULL, the flow is treated as exact match * flow. Otherwise, it is treated as a wildcarded flow, except the mask * does not include any don't care bit. * @net: Used to determine per-namespace field support. * @match: receives the extracted flow match information. * @nla_key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. The fields should of the packet that triggered the creation * of this flow. * @nla_mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_* * Netlink attribute specifies the mask field of the wildcarded flow. * @log: Boolean to allow kernel error logging. Normally true, but when * probing for feature compatibility this should be passed in as false to * suppress unnecessary error logging.
*/ int ovs_nla_get_match(struct net *net, struct sw_flow_match *match, conststruct nlattr *nla_key, conststruct nlattr *nla_mask, bool log)
{ conststruct nlattr *a[OVS_KEY_ATTR_MAX + 1]; struct nlattr *newmask = NULL;
u64 key_attrs = 0;
u64 mask_attrs = 0; int err;
err = parse_flow_nlattrs(nla_key, a, &key_attrs, log); if (err) return err;
err = parse_vlan_from_nlattrs(match, &key_attrs, a, false, log); if (err) return err;
err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log); if (err) return err;
if (match->mask) { if (!nla_mask) { /* Create an exact match mask. We need to set to 0xff * all the 'match->mask' fields that have been touched * in 'match->key'. We cannot simply memset * 'match->mask', because padding bytes and fields not * specified in 'match->key' should be left to 0. * Instead, we use a stream of netlink attributes, * copied from 'key' and set to 0xff. * ovs_key_from_nlattrs() will take care of filling * 'match->mask' appropriately.
*/
newmask = kmemdup(nla_key,
nla_total_size(nla_len(nla_key)),
GFP_KERNEL); if (!newmask) return -ENOMEM;
mask_set_nlattr(newmask, 0xff);
/* The userspace does not send tunnel attributes that * are 0, but we should not wildcard them nonetheless.
*/ if (match->key->tun_proto)
SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
0xff, true);
nla_mask = newmask;
}
err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log); if (err) goto free_newmask;
/* Always match on tci. */
SW_FLOW_KEY_PUT(match, eth.vlan.tci, htons(0xffff), true);
SW_FLOW_KEY_PUT(match, eth.cvlan.tci, htons(0xffff), true);
err = parse_vlan_from_nlattrs(match, &mask_attrs, a, true, log); if (err) goto free_newmask;
err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true,
log); if (err) goto free_newmask;
}
if (!match_validate(match, key_attrs, mask_attrs, log))
err = -EINVAL;
/* If UFID was not provided, use unmasked key. */
new_key = kmalloc(sizeof(*new_key), GFP_KERNEL); if (!new_key) return -ENOMEM;
memcpy(new_key, key, sizeof(*key));
sfid->unmasked_key = new_key;
/** * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key. * @net: Network namespace. * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack * metadata. * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink * attributes. * @attrs: Bit mask for the netlink attributes included in @a. * @log: Boolean to allow kernel error logging. Normally true, but when * probing for feature compatibility this should be passed in as false to * suppress unnecessary error logging. * * This parses a series of Netlink attributes that form a flow key, which must * take the same form accepted by flow_from_nlattrs(), but only enough of it to * get the metadata, that is, the parts of the flow key that cannot be * extracted from the packet itself. * * This must be called before the packet key fields are filled in 'key'.
*/
int ovs_nla_get_flow_metadata(struct net *net, conststruct nlattr *a[OVS_KEY_ATTR_MAX + 1],
u64 attrs, struct sw_flow_key *key, bool log)
{ struct sw_flow_match match;
if (swkey->eth.vlan.tci || eth_type_vlan(swkey->eth.type)) { if (ovs_nla_put_vlan(skb, &output->eth.vlan, is_mask)) goto nla_put_failure;
encap = nla_nest_start_noflag(skb, OVS_KEY_ATTR_ENCAP); if (!swkey->eth.vlan.tci) goto unencap;
if (swkey->eth.cvlan.tci || eth_type_vlan(swkey->eth.type)) { if (ovs_nla_put_vlan(skb, &output->eth.cvlan, is_mask)) goto nla_put_failure;
in_encap = nla_nest_start_noflag(skb,
OVS_KEY_ATTR_ENCAP); if (!swkey->eth.cvlan.tci) goto unencap;
}
}
if (swkey->eth.type == htons(ETH_P_802_2)) { /* * Ethertype 802.2 is represented in the netlink with omitted * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and * 0xffff in the mask attribute. Ethertype can also * be wildcarded.
*/ if (is_mask && output->eth.type) if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
output->eth.type)) goto nla_put_failure; goto unencap;
}
}
if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type)) goto nla_put_failure;
if (eth_type_vlan(swkey->eth.type)) { /* There are 3 VLAN tags, we don't know anything about the rest * of the packet, so truncate here.
*/
WARN_ON_ONCE(!(encap && in_encap)); goto unencap;
}
if (swkey->eth.type == htons(ETH_P_IP)) { struct ovs_key_ipv4 *ipv4_key;
unencap: if (in_encap)
nla_nest_end(skb, in_encap); if (encap)
nla_nest_end(skb, encap);
return 0;
nla_put_failure: return -EMSGSIZE;
}
int ovs_nla_put_key(conststruct sw_flow_key *swkey, conststruct sw_flow_key *output, int attr, bool is_mask, struct sk_buff *skb)
{ int err; struct nlattr *nla;
nla = nla_nest_start_noflag(skb, attr); if (!nla) return -EMSGSIZE;
err = __ovs_nla_put_key(swkey, output, is_mask, skb); if (err) return err;
nla_nest_end(skb, nla);
return 0;
}
/* Called with ovs_mutex or RCU read lock. */ int ovs_nla_put_identifier(conststruct sw_flow *flow, struct sk_buff *skb)
{ if (ovs_identifier_is_ufid(&flow->id)) return nla_put(skb, OVS_FLOW_ATTR_UFID, flow->id.ufid_len,
flow->id.ufid);
sfa = kmalloc(kmalloc_size_roundup(sizeof(*sfa) + size), GFP_KERNEL); if (!sfa) return ERR_PTR(-ENOMEM);
sfa->actions_len = 0; return sfa;
}
staticvoid ovs_nla_free_nested_actions(conststruct nlattr *actions, int len);
staticvoid ovs_nla_free_check_pkt_len_action(conststruct nlattr *action)
{ conststruct 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;
}
}
}
staticvoid ovs_nla_free_clone_action(conststruct nlattr *action)
{ conststruct 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;
}
}
switch (nla_type(a)) { case OVS_DEC_TTL_ATTR_ACTION:
ovs_nla_free_nested_actions(nla_data(a), nla_len(a)); break;
}
}
staticvoid ovs_nla_free_sample_action(conststruct nlattr *action)
{ conststruct 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;
}
}
/* Schedules 'sf_acts' to be freed after the next RCU grace period.
* The caller must hold rcu_read_lock for this to be sensible. */ void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts)
{
call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions);
}
staticstruct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_len, bool log)
{
struct sw_flow_actions *acts; int new_acts_size;
size_t req_size = NLA_ALIGN(attr_len); int next_offset = offsetof(struct sw_flow_actions, actions) +
(*sfa)->actions_len;
if (req_size <= (ksize(*sfa) - next_offset)) goto out;
/* When both skb and flow may be changed, put the sample * into a deferred fifo. On the other hand, if only skb * may be modified, the actions can be executed in place. * * Do this analysis at the flow installation time. * Set 'clone_action->exec' to true if the actions can be * executed without being deferred. * * If the sample is the last action, it can always be excuted * rather than deferred.
*/
arg.exec = last || !actions_may_change_flow(actions);
arg.probability = nla_get_u32(probability);
/* We need to store the options in the action itself since * everything else will go away after flow setup. We can append * it to tun_info and then point there.
*/
ip_tunnel_info_opts_set(tun_info,
TUN_METADATA_OPTS(&key, key.tun_opts_len),
key.tun_opts_len, dst_opt_type);
add_nested_action_end(*sfa, start);
/* Return false if there are any non-masked bits set. * Mask follows data immediately, before any netlink padding.
*/ staticbool validate_masked(u8 *data, int len)
{
u8 *mask = data + len;
while (len--) if (*data++ & ~*mask++) returnfalse;
/* There can be only one key in a action */ if (!nla_ok(ovs_key, nla_len(a)) ||
nla_total_size(nla_len(ovs_key)) != nla_len(a)) return -EINVAL;
key_len = nla_len(ovs_key); if (masked)
key_len /= 2;
if (key_type > OVS_KEY_ATTR_MAX ||
!check_attr_len(key_len, ovs_key_lens[key_type].len)) return -EINVAL;
if (masked && !validate_masked(nla_data(ovs_key), key_len)) return -EINVAL;
switch (key_type) { case OVS_KEY_ATTR_PRIORITY: case OVS_KEY_ATTR_SKB_MARK: case OVS_KEY_ATTR_CT_MARK: case OVS_KEY_ATTR_CT_LABELS: break;
case OVS_KEY_ATTR_ETHERNET: if (mac_proto != MAC_PROTO_ETHERNET) return -EINVAL; break;
case OVS_KEY_ATTR_TUNNEL: { int err;
if (masked) return -EINVAL; /* Masked tunnel set not supported. */
*skip_copy = true;
err = validate_and_copy_set_tun(a, sfa, log); if (err) return err; break;
} case OVS_KEY_ATTR_IPV4: { conststruct ovs_key_ipv4 *ipv4_key;
if (eth_type != htons(ETH_P_IP)) return -EINVAL;
ipv4_key = nla_data(ovs_key);
if (masked) { conststruct ovs_key_ipv4 *mask = ipv4_key + 1;
/* Non-writeable fields. */ if (mask->ipv4_proto || mask->ipv4_frag) return -EINVAL;
} else { if (ipv4_key->ipv4_proto != flow_key->ip.proto) return -EINVAL;
if (ipv4_key->ipv4_frag != flow_key->ip.frag) return -EINVAL;
} break;
} case OVS_KEY_ATTR_IPV6: { conststruct ovs_key_ipv6 *ipv6_key;
if (eth_type != htons(ETH_P_IPV6)) return -EINVAL;
ipv6_key = nla_data(ovs_key);
if (masked) { conststruct ovs_key_ipv6 *mask = ipv6_key + 1;
/* Non-writeable fields. */ if (mask->ipv6_proto || mask->ipv6_frag) return -EINVAL;
/* Invalid bits in the flow label mask? */ if (ntohl(mask->ipv6_label) & 0xFFF00000) return -EINVAL;
} else { if (ipv6_key->ipv6_proto != flow_key->ip.proto) return -EINVAL;
if (ipv6_key->ipv6_frag != flow_key->ip.frag) return -EINVAL;
} if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000) return -EINVAL;
break;
} case OVS_KEY_ATTR_TCP: if ((eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6)) ||
flow_key->ip.proto != IPPROTO_TCP) return -EINVAL;
break;
case OVS_KEY_ATTR_UDP: if ((eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6)) ||
flow_key->ip.proto != IPPROTO_UDP) return -EINVAL;
break;
case OVS_KEY_ATTR_MPLS: if (!eth_p_mpls(eth_type)) return -EINVAL; break;
case OVS_KEY_ATTR_SCTP: if ((eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6)) ||
flow_key->ip.proto != IPPROTO_SCTP) return -EINVAL;
break;
case OVS_KEY_ATTR_NSH: if (eth_type != htons(ETH_P_NSH)) return -EINVAL; if (!validate_nsh(nla_data(a), masked, false, log)) return -EINVAL; break;
default: return -EINVAL;
}
/* Convert non-masked non-tunnel set actions to masked set actions. */ if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) { int start, len = key_len * 2; struct nlattr *at;
case OVS_ACTION_ATTR_PUSH_MPLS: { conststruct ovs_action_push_mpls *mpls = nla_data(a);
if (!eth_p_mpls(mpls->mpls_ethertype)) return -EINVAL; /* Prohibit push MPLS other than to a white list * for packets that have a known tag order.
*/ if (vlan_tci & htons(VLAN_CFI_MASK) ||
(eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6) &&
eth_type != htons(ETH_P_ARP) &&
eth_type != htons(ETH_P_RARP) &&
!eth_p_mpls(eth_type))) return -EINVAL;
eth_type = mpls->mpls_ethertype;
mpls_label_count++; break;
}
case OVS_ACTION_ATTR_POP_MPLS: {
__be16 proto; if (vlan_tci & htons(VLAN_CFI_MASK) ||
!eth_p_mpls(eth_type)) return -EINVAL;
/* Disallow subsequent L2.5+ set actions and mpls_pop * actions once the last MPLS label in the packet is * popped as there is no check here to ensure that * the new eth type is valid and thus set actions could * write off the end of the packet or otherwise corrupt * it. * * Support for these actions is planned using packet * recirculation.
*/
proto = nla_get_be16(a);
if (proto == htons(ETH_P_TEB) &&
mac_proto != MAC_PROTO_NONE) return -EINVAL;
case OVS_ACTION_ATTR_SET:
err = validate_set(a, key, sfa,
&skip_copy, mac_proto, eth_type, false, log); if (err) return err; break;
case OVS_ACTION_ATTR_SET_MASKED:
err = validate_set(a, key, sfa,
&skip_copy, mac_proto, eth_type, true, log); if (err) return err; break;
case OVS_ACTION_ATTR_SAMPLE: { bool last = nla_is_last(a, rem);
err = validate_and_copy_sample(net, a, key, sfa,
eth_type, vlan_tci,
mpls_label_count,
log, last, depth); if (err) return err;
skip_copy = true; break;
}
case OVS_ACTION_ATTR_CT:
err = ovs_ct_copy_action(net, a, key, sfa, log); if (err) return err;
skip_copy = true; break;
case OVS_ACTION_ATTR_CT_CLEAR: break;
case OVS_ACTION_ATTR_PUSH_ETH: /* Disallow pushing an Ethernet header if one
* is already present */ if (mac_proto != MAC_PROTO_NONE) return -EINVAL;
mac_proto = MAC_PROTO_ETHERNET; break;
case OVS_ACTION_ATTR_POP_ETH: if (mac_proto != MAC_PROTO_ETHERNET) return -EINVAL; if (vlan_tci & htons(VLAN_CFI_MASK)) return -EINVAL;
mac_proto = MAC_PROTO_NONE; break;
case OVS_ACTION_ATTR_PUSH_NSH: if (mac_proto != MAC_PROTO_ETHERNET) {
u8 next_proto;
next_proto = tun_p_from_eth_p(eth_type); if (!next_proto) return -EINVAL;
}
mac_proto = MAC_PROTO_NONE; if (!validate_nsh(nla_data(a), false, true, true)) return -EINVAL; break;
case OVS_ACTION_ATTR_POP_NSH: {
__be16 inner_proto;
if (eth_type != htons(ETH_P_NSH)) return -EINVAL;
inner_proto = tun_p_to_eth_p(key->nsh.base.np); if (!inner_proto) return -EINVAL; if (key->nsh.base.np == TUN_P_ETHERNET)
mac_proto = MAC_PROTO_ETHERNET; else
mac_proto = MAC_PROTO_NONE; break;
}
case OVS_ACTION_ATTR_METER: /* Non-existent meters are simply ignored. */ break;
case OVS_ACTION_ATTR_CLONE: { bool last = nla_is_last(a, rem);
err = validate_and_copy_clone(net, a, key, sfa,
eth_type, vlan_tci,
mpls_label_count,
log, last, depth); if (err) return err;
skip_copy = true; break;
}
case OVS_ACTION_ATTR_CHECK_PKT_LEN: { bool last = nla_is_last(a, rem);
err = validate_and_copy_check_pkt_len(net, a, key, sfa,
eth_type,
vlan_tci,
mpls_label_count,
log, last,
depth); if (err) return err;
skip_copy = true; break;
}
case OVS_ACTION_ATTR_DEC_TTL:
err = validate_and_copy_dec_ttl(net, a, key, sfa,
eth_type, vlan_tci,
mpls_label_count, log,
depth); if (err) return err;
skip_copy = true; break;
case OVS_ACTION_ATTR_DROP: if (!nla_is_last(a, rem)) return -EINVAL; break;
case OVS_ACTION_ATTR_PSAMPLE:
err = validate_psample(a); if (err) return err; break;
default:
OVS_NLERR(log, "Unknown Action type %d", type); return -EINVAL;
} if (!skip_copy) {
err = copy_action(a, sfa, log); if (err) return err;
}
}
if (rem > 0) return -EINVAL;
return 0;
}
/* 'key' must be the masked key. */ int ovs_nla_copy_actions(struct net *net, conststruct nlattr *attr, conststruct sw_flow_key *key, struct sw_flow_actions **sfa, bool log)
{ int err;
u32 mpls_label_count = 0;
*sfa = nla_alloc_flow_actions(nla_len(attr)); if (IS_ERR(*sfa)) return PTR_ERR(*sfa);
if (eth_p_mpls(key->eth.type))
mpls_label_count = hweight_long(key->mpls.num_labels_mask);
staticint clone_action_to_attr(conststruct nlattr *attr, struct sk_buff *skb)
{ struct nlattr *start; int err = 0, rem = nla_len(attr);
start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CLONE); if (!start) return -EMSGSIZE;
/* Skipping the OVS_CLONE_ATTR_EXEC that is always the first attribute. */
attr = nla_next(nla_data(attr), &rem);
err = ovs_nla_put_actions(attr, rem, skb);
if (err)
nla_nest_cancel(skb, start); else
nla_nest_end(skb, start);
/* Revert the conversion we did from a non-masked set action to * masked set action.
*/
nla = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET); if (!nla) return -EMSGSIZE;
if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key))) return -EMSGSIZE;
nla_nest_end(skb, nla); return 0;
}
int ovs_nla_put_actions(conststruct nlattr *attr, int len, struct sk_buff *skb)
{ conststruct nlattr *a; int rem, err;
nla_for_each_attr(a, attr, len, rem) { int type = nla_type(a);
switch (type) { case OVS_ACTION_ATTR_SET:
err = set_action_to_attr(a, skb); if (err) return err; break;
case OVS_ACTION_ATTR_SET_TO_MASKED:
err = masked_set_action_to_set_action_attr(a, skb); if (err) return err; break;
case OVS_ACTION_ATTR_SAMPLE:
err = sample_action_to_attr(a, skb); if (err) return err; break;
case OVS_ACTION_ATTR_CT:
err = ovs_ct_action_to_attr(nla_data(a), skb); if (err) return err; break;
case OVS_ACTION_ATTR_CLONE:
err = clone_action_to_attr(a, skb); if (err) return err; break;
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
err = check_pkt_len_action_to_attr(a, skb); if (err) return err; break;
case OVS_ACTION_ATTR_DEC_TTL:
err = dec_ttl_action_to_attr(a, skb); if (err) return err; break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.