mirror of
https://github.com/openvswitch/ovs
synced 2025-10-25 15:07:05 +00:00
datapath: Allow a packet with no input port to omit OVS_KEY_ATTR_IN_PORT.
When ovs-vswitchd executes actions on a synthesized packet, that is, on a packet that is not being forwarded from any particular port but is being generated by ovs-vswitchd itself or by an OpenFlow controller (using a OFPT_PACKET_OUT message with an in_port of OFPP_NONE), there is no good choice for the in_port to pass to the kernel in the flow in the OVS_PACKET_CMD_EXECUTE message. This commit allows ovs-vswitchd to omit the in_port entirely in this case. This fixes a bug in OFPT_PACKET_OUT: using an in_port of OFPP_NONE would cause the packet to be dropped by the kernel, since that's an invalid input port. Signed-off-by: Ben Pfaff <blp@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com> Reported-by: Aaron Rosen <arosen@clemson.edu>
This commit is contained in:
@@ -624,7 +624,7 @@ static const u32 key_lens[OVS_KEY_ATTR_MAX + 1] = {
|
|||||||
* This state machine accepts the following forms, with [] for optional
|
* This state machine accepts the following forms, with [] for optional
|
||||||
* elements and | for alternatives:
|
* elements and | for alternatives:
|
||||||
*
|
*
|
||||||
* [tun_id] in_port ethernet [8021q] [ethertype \
|
* [tun_id] [in_port] ethernet [8021q] [ethertype \
|
||||||
* [IPv4 [TCP|UDP|ICMP] | IPv6 [TCP|UDP|ICMPv6 [ND]] | ARP]]
|
* [IPv4 [TCP|UDP|ICMP] | IPv6 [TCP|UDP|ICMPv6 [ND]] | ARP]]
|
||||||
*/
|
*/
|
||||||
int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
|
int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
|
||||||
@@ -637,6 +637,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
|
|||||||
int key_len;
|
int key_len;
|
||||||
|
|
||||||
memset(swkey, 0, sizeof(*swkey));
|
memset(swkey, 0, sizeof(*swkey));
|
||||||
|
swkey->eth.in_port = USHRT_MAX;
|
||||||
swkey->eth.type = htons(ETH_P_802_2);
|
swkey->eth.type = htons(ETH_P_802_2);
|
||||||
key_len = SW_FLOW_KEY_OFFSET(eth);
|
key_len = SW_FLOW_KEY_OFFSET(eth);
|
||||||
|
|
||||||
@@ -671,6 +672,8 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
|
|||||||
swkey->eth.in_port = nla_get_u32(nla);
|
swkey->eth.in_port = nla_get_u32(nla);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_ETHERNET):
|
||||||
|
case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_ETHERNET):
|
||||||
case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
|
case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
|
||||||
eth_key = nla_data(nla);
|
eth_key = nla_data(nla);
|
||||||
memcpy(swkey->eth.src, eth_key->eth_src, ETH_ALEN);
|
memcpy(swkey->eth.src, eth_key->eth_src, ETH_ALEN);
|
||||||
@@ -888,6 +891,7 @@ int flow_metadata_from_nlattrs(u16 *in_port, __be64 *tun_id,
|
|||||||
u16 prev_type;
|
u16 prev_type;
|
||||||
int rem;
|
int rem;
|
||||||
|
|
||||||
|
*in_port = USHRT_MAX;
|
||||||
*tun_id = 0;
|
*tun_id = 0;
|
||||||
|
|
||||||
prev_type = OVS_KEY_ATTR_UNSPEC;
|
prev_type = OVS_KEY_ATTR_UNSPEC;
|
||||||
@@ -910,18 +914,13 @@ int flow_metadata_from_nlattrs(u16 *in_port, __be64 *tun_id,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto done;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_type = type;
|
prev_type = type;
|
||||||
}
|
}
|
||||||
if (rem)
|
if (rem)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
done:
|
|
||||||
if (prev_type == OVS_KEY_ATTR_UNSPEC ||
|
|
||||||
prev_type == OVS_KEY_ATTR_TUN_ID)
|
|
||||||
return -EINVAL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,7 +937,8 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
|
|||||||
if (swkey->eth.tun_id != cpu_to_be64(0))
|
if (swkey->eth.tun_id != cpu_to_be64(0))
|
||||||
NLA_PUT_BE64(skb, OVS_KEY_ATTR_TUN_ID, swkey->eth.tun_id);
|
NLA_PUT_BE64(skb, OVS_KEY_ATTR_TUN_ID, swkey->eth.tun_id);
|
||||||
|
|
||||||
NLA_PUT_U32(skb, OVS_KEY_ATTR_IN_PORT, swkey->eth.in_port);
|
if (swkey->eth.in_port != USHRT_MAX)
|
||||||
|
NLA_PUT_U32(skb, OVS_KEY_ATTR_IN_PORT, swkey->eth.in_port);
|
||||||
|
|
||||||
nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
|
nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
|
||||||
if (!nla)
|
if (!nla)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct sw_flow_actions {
|
|||||||
struct sw_flow_key {
|
struct sw_flow_key {
|
||||||
struct {
|
struct {
|
||||||
__be64 tun_id; /* Encapsulating tunnel ID. */
|
__be64 tun_id; /* Encapsulating tunnel ID. */
|
||||||
u16 in_port; /* Input switch port. */
|
u16 in_port; /* Input switch port (or USHRT_MAX). */
|
||||||
u8 src[ETH_ALEN]; /* Ethernet source address. */
|
u8 src[ETH_ALEN]; /* Ethernet source address. */
|
||||||
u8 dst[ETH_ALEN]; /* Ethernet destination address. */
|
u8 dst[ETH_ALEN]; /* Ethernet destination address. */
|
||||||
__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
|
__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
|
||||||
|
|||||||
@@ -654,6 +654,12 @@ dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flow->in_port < OFPP_MAX
|
||||||
|
? flow->in_port >= MAX_PORTS
|
||||||
|
: flow->in_port != OFPP_LOCAL && flow->in_port != OFPP_NONE) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,9 +985,11 @@ dpif_netdev_execute(struct dpif *dpif,
|
|||||||
}
|
}
|
||||||
|
|
||||||
flow_extract(©, 0, -1, &key);
|
flow_extract(©, 0, -1, &key);
|
||||||
dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
|
error = dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
|
||||||
|
if (!error) {
|
||||||
error = dp_netdev_execute_actions(dp, ©, &key, actions, actions_len);
|
error = dp_netdev_execute_actions(dp, ©, &key,
|
||||||
|
actions, actions_len);
|
||||||
|
}
|
||||||
if (mutates) {
|
if (mutates) {
|
||||||
ofpbuf_uninit(©);
|
ofpbuf_uninit(©);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -713,8 +713,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
|
|||||||
nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id);
|
nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT,
|
if (flow->in_port != OFPP_NONE) {
|
||||||
ofp_port_to_odp_port(flow->in_port));
|
nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT,
|
||||||
|
ofp_port_to_odp_port(flow->in_port));
|
||||||
|
}
|
||||||
|
|
||||||
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
|
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
|
||||||
sizeof *eth_key);
|
sizeof *eth_key);
|
||||||
@@ -830,6 +832,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
|
|||||||
|
|
||||||
memset(flow, 0, sizeof *flow);
|
memset(flow, 0, sizeof *flow);
|
||||||
flow->dl_type = htons(FLOW_DL_TYPE_NONE);
|
flow->dl_type = htons(FLOW_DL_TYPE_NONE);
|
||||||
|
flow->in_port = OFPP_NONE;
|
||||||
|
|
||||||
prev_type = OVS_KEY_ATTR_UNSPEC;
|
prev_type = OVS_KEY_ATTR_UNSPEC;
|
||||||
NL_ATTR_FOR_EACH (nla, left, key, key_len) {
|
NL_ATTR_FOR_EACH (nla, left, key, key_len) {
|
||||||
@@ -865,6 +868,8 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
|
|||||||
flow->in_port = odp_port_to_ofp_port(nl_attr_get_u32(nla));
|
flow->in_port = odp_port_to_ofp_port(nl_attr_get_u32(nla));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_ETHERNET):
|
||||||
|
case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_ETHERNET):
|
||||||
case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
|
case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
|
||||||
eth_key = nl_attr_get(nla);
|
eth_key = nl_attr_get(nla);
|
||||||
memcpy(flow->dl_src, eth_key->eth_src, ETH_ADDR_LEN);
|
memcpy(flow->dl_src, eth_key->eth_src, ETH_ADDR_LEN);
|
||||||
|
|||||||
Reference in New Issue
Block a user