X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=8a55001254e8e9488553a634068cc4763e3a615c;hb=29722bcc53774a763c583dfeec12af492a035008;hp=544f8cdffec29a164d389c11408214a5d3cdb58f;hpb=aa5a8fdca51153d25be8a90e3121cdeff011b684;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 544f8cdf..8a550012 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -51,6 +51,7 @@ #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); @@ -358,7 +359,6 @@ static void copy_and_csum_skb(struct sk_buff *skb, void *to) 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); @@ -440,7 +440,11 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i } } - 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); @@ -483,8 +487,14 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *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) @@ -701,6 +711,9 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) 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; @@ -774,6 +787,8 @@ int dp_min_mtu(const struct datapath *dp) continue; dev_mtu = vport_get_mtu(p); + if (!dev_mtu) + continue; if (!mtu || dev_mtu < mtu) mtu = dev_mtu; } @@ -828,7 +843,6 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, struct nlattr *nla; unsigned long used; u8 tcp_flags; - int nla_len; int err; sf_acts = rcu_dereference_protected(flow->sf_acts, @@ -856,7 +870,7 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, 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); @@ -864,23 +878,20 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, 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); @@ -1293,7 +1304,7 @@ static int odp_dp_cmd_validate(struct nlattr *a[ODP_DP_ATTR_MAX + 1]) 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. */ @@ -1445,12 +1456,20 @@ static int odp_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) 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(); @@ -1587,6 +1606,7 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, 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, @@ -1608,7 +1628,9 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, 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) @@ -1652,7 +1674,7 @@ static struct sk_buff *odp_vport_cmd_build_info(struct vport *vport, u32 pid, 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. */