#include "flow.h"
#include "loop_counter.h"
#include "table.h"
+#include "vlan.h"
#include "vport-internal_dev.h"
int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
get_skb_csum_pointers(skb, &csum_start, &csum_offset);
csum_start -= skb_headroom(skb);
- BUG_ON(csum_start >= skb_headlen(skb));
skb_copy_bits(skb, 0, to, csum_start);
}
}
- return queue_control_packets(dp, skb, upcall_info);
+ err = queue_control_packets(dp, skb, upcall_info);
+ if (err)
+ goto err;
+
+ return 0;
err_kfree_skb:
kfree_skb(skb);
nskb = skb->next;
skb->next = NULL;
+ err = vlan_deaccel_tag(skb);
+ if (unlikely(err))
+ goto err_kfree_skbs;
+
+ if (nla_attr_size(skb->len) > USHRT_MAX)
+ goto err_kfree_skbs;
+
len = sizeof(struct odp_header);
- len += nla_total_size(4); /* ODP_PACKET_ATTR_TYPE. */
len += nla_total_size(skb->len);
len += nla_total_size(FLOW_BUFSIZE);
if (upcall_info->userdata)
err = -EINVAL;
if (!a[ODP_PACKET_ATTR_PACKET] || !a[ODP_PACKET_ATTR_ACTIONS] ||
nla_len(a[ODP_PACKET_ATTR_PACKET]) < ETH_HLEN)
- goto exit;
+ goto err;
err = validate_actions(a[ODP_PACKET_ATTR_ACTIONS]);
if (err)
- goto exit;
+ goto err;
packet = skb_clone(skb, GFP_KERNEL);
err = -ENOMEM;
if (!packet)
- goto exit;
+ goto err;
packet->data = nla_data(a[ODP_PACKET_ATTR_PACKET]);
packet->len = nla_len(a[ODP_PACKET_ATTR_PACKET]);
else
packet->protocol = htons(ETH_P_802_2);
+ /* Initialize OVS_CB (it came from Netlink so might not be zeroed). */
+ memset(OVS_CB(packet), 0, sizeof(struct ovs_skb_cb));
+
err = flow_extract(packet, -1, &key, &is_frag);
if (err)
- goto exit;
+ goto err_kfree_skb;
rcu_read_lock();
dp = get_dp(odp_header->dp_ifindex);
err = -ENODEV;
- if (dp)
- err = execute_actions(dp, packet, &key,
- nla_data(a[ODP_PACKET_ATTR_ACTIONS]),
- nla_len(a[ODP_PACKET_ATTR_ACTIONS]));
+ if (!dp)
+ goto err_unlock;
+ err = execute_actions(dp, packet, &key,
+ nla_data(a[ODP_PACKET_ATTR_ACTIONS]),
+ nla_len(a[ODP_PACKET_ATTR_ACTIONS]));
rcu_read_unlock();
+ return err;
-exit:
+err_unlock:
+ rcu_read_unlock();
+err_kfree_skb:
+ kfree_skb(packet);
+err:
return err;
}
continue;
dev_mtu = vport_get_mtu(p);
+ if (!dev_mtu)
+ continue;
if (!mtu || dev_mtu < mtu)
mtu = dev_mtu;
}
struct nlattr *nla;
unsigned long used;
u8 tcp_flags;
- int nla_len;
int err;
sf_acts = rcu_dereference_protected(flow->sf_acts,
spin_unlock_bh(&flow->lock);
if (used)
- NLA_PUT_MSECS(skb, ODP_FLOW_ATTR_USED, used);
+ NLA_PUT_U64(skb, ODP_FLOW_ATTR_USED, flow_used_time(used));
if (stats.n_packets)
NLA_PUT(skb, ODP_FLOW_ATTR_STATS, sizeof(struct odp_flow_stats), &stats);
if (tcp_flags)
NLA_PUT_U8(skb, ODP_FLOW_ATTR_TCP_FLAGS, tcp_flags);
- /* If ODP_FLOW_ATTR_ACTIONS doesn't fit, and this is the first flow to
- * be dumped into 'skb', then expand the skb. This is unusual for
- * Netlink but individual action lists can be longer than a page and
- * thus entirely undumpable if we didn't do this. */
- nla_len = nla_total_size(sf_acts->actions_len);
- if (nla_len > skb_tailroom(skb) && !skb_orig_len) {
- int hdr_off = (unsigned char *)odp_header - skb->data;
-
- err = pskb_expand_head(skb, 0, nla_len - skb_tailroom(skb), GFP_KERNEL);
- if (err)
- goto error;
-
- odp_header = (struct odp_header *)(skb->data + hdr_off);
- }
- nla = nla_nest_start(skb, ODP_FLOW_ATTR_ACTIONS);
- memcpy(__skb_put(skb, sf_acts->actions_len), sf_acts->actions, sf_acts->actions_len);
- nla_nest_end(skb, nla);
+ /* If ODP_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
+ * this is the first flow to be dumped into 'skb'. This is unusual for
+ * Netlink but individual action lists can be longer than
+ * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this.
+ * The userspace caller can always fetch the actions separately if it
+ * really wants them. (Most userspace callers in fact don't care.)
+ *
+ * This can only fail for dump operations because the skb is always
+ * properly sized for single flows.
+ */
+ err = nla_put(skb, ODP_FLOW_ATTR_ACTIONS, sf_acts->actions_len,
+ sf_acts->actions);
+ if (err < 0 && skb_orig_len)
+ goto error;
return genlmsg_end(skb, odp_header);
return -EINVAL;
}
- return VERIFY_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1);
+ return CHECK_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1);
}
/* Called with genl_mutex and optionally with RTNL lock also. */
list_del(&dp->list_node);
dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
+ /* rtnl_unlock() will wait until all the references to devices that
+ * are pending unregistration have been dropped. We do it here to
+ * ensure that any internal devices (which contain DP pointers) are
+ * fully destroyed before freeing the datapath.
+ */
+ rtnl_unlock();
+
call_rcu(&dp->rcu, destroy_dp_rcu);
module_put(THIS_MODULE);
genl_notify(reply, genl_info_net(info), info->snd_pid,
dp_datapath_multicast_group.id, info->nlhdr, GFP_KERNEL);
- err = 0;
+
+ return 0;
exit_unlock:
rtnl_unlock();
struct odp_header *odp_header;
struct nlattr *nla;
int ifindex, iflink;
+ int mtu;
int err;
odp_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family,
NLA_PUT(skb, ODP_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport));
- NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, vport_get_mtu(vport));
+ mtu = vport_get_mtu(vport);
+ if (mtu)
+ NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, mtu);
err = vport_get_options(vport, skb);
if (err == -EMSGSIZE)
static int odp_vport_cmd_validate(struct nlattr *a[ODP_VPORT_ATTR_MAX + 1])
{
- return VERIFY_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1);
+ return CHECK_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1);
}
/* Called with RTNL lock or RCU read lock. */