X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=fc00d78788a567c35a77d5505bc2ab699b726c6e;hb=0b9275b2c7ed2f88491898345e03618dbfbf4b0f;hp=531afebca13c603c343885a45f844a0d519146ba;hpb=9d1e0023e7e88570d112258d235e03591dfe2b1b;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 531afebc..fc00d787 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -49,7 +49,6 @@ #include "datapath.h" #include "actions.h" #include "flow.h" -#include "loop_counter.h" #include "table.h" #include "vlan.h" #include "vport-internal_dev.h" @@ -267,8 +266,6 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) struct datapath *dp = p->dp; struct dp_stats_percpu *stats; int stats_counter_off; - struct sw_flow_actions *acts; - struct loop_counter *loop; int error; OVS_CB(skb)->vport = p; @@ -313,32 +310,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) stats_counter_off = offsetof(struct dp_stats_percpu, n_hit); flow_used(OVS_CB(skb)->flow, skb); - - acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); - - /* Check whether we've looped too much. */ - loop = loop_get_counter(); - if (unlikely(++loop->count > MAX_LOOPS)) - loop->looping = true; - if (unlikely(loop->looping)) { - loop_suppress(dp, acts); - kfree_skb(skb); - goto out_loop; - } - - /* Execute actions. */ - execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions, - acts->actions_len); - - /* Check whether sub-actions looped too much. */ - if (unlikely(loop->looping)) - loop_suppress(dp, acts); - -out_loop: - /* Decrement loop counter. */ - if (!--loop->count) - loop->looping = false; - loop_put_counter(); + execute_actions(dp, skb); out: /* Update datapath statistics. */ @@ -359,7 +331,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); @@ -441,7 +412,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); @@ -467,14 +442,8 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *skb, { u32 group = packet_mc_group(dp, upcall_info->cmd); struct sk_buff *nskb; - int port_no; int err; - if (OVS_CB(skb)->vport) - port_no = OVS_CB(skb)->vport->port_no; - else - port_no = ODPP_LOCAL; - do { struct odp_header *upcall; struct sk_buff *user_skb; /* to be queued to userspace */ @@ -488,6 +457,9 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *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(skb->len); len += nla_total_size(FLOW_BUFSIZE); @@ -671,28 +643,32 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) { struct odp_header *odp_header = info->userhdr; struct nlattr **a = info->attrs; + struct sw_flow_actions *acts; struct sk_buff *packet; - struct sw_flow_key key; + struct sw_flow *flow; struct datapath *dp; struct ethhdr *eth; bool is_frag; + int len; int err; 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); + len = nla_len(a[ODP_PACKET_ATTR_PACKET]); + packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL); err = -ENOMEM; if (!packet) - goto exit; - packet->data = nla_data(a[ODP_PACKET_ATTR_PACKET]); - packet->len = nla_len(a[ODP_PACKET_ATTR_PACKET]); + goto err; + skb_reserve(packet, NET_IP_ALIGN); + + memcpy(__skb_put(packet, len), nla_data(a[ODP_PACKET_ATTR_PACKET]), len); skb_reset_mac_header(packet); eth = eth_hdr(packet); @@ -705,23 +681,43 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) else packet->protocol = htons(ETH_P_802_2); - err = flow_extract(packet, -1, &key, &is_frag); + /* Build an sw_flow for sending this packet. */ + flow = flow_alloc(); + err = PTR_ERR(flow); + if (IS_ERR(flow)) + goto err_kfree_skb; + + err = flow_extract(packet, -1, &flow->key, &is_frag); if (err) - goto exit; + goto err_flow_put; + flow->tbl_node.hash = flow_hash(&flow->key); + + acts = flow_actions_alloc(a[ODP_PACKET_ATTR_ACTIONS]); + err = PTR_ERR(acts); + if (IS_ERR(acts)) + goto err_flow_put; + rcu_assign_pointer(flow->sf_acts, acts); - /* Initialize OVS_CB (it came from Netlink so might not be zeroed). */ - memset(OVS_CB(packet), 0, sizeof(struct ovs_skb_cb)); + OVS_CB(packet)->flow = flow; 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); rcu_read_unlock(); -exit: + flow_put(flow); + return err; + +err_unlock: + rcu_read_unlock(); +err_flow_put: + flow_put(flow); +err_kfree_skb: + kfree_skb(packet); +err: return err; } @@ -1298,7 +1294,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. */ @@ -1450,12 +1446,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(); @@ -1660,7 +1664,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. */