X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=46bb6961cef5cbd51f5303b184e5e25790984ddc;hb=7dab847a19503f537c57c2215748f0b50b94f51e;hp=08b620036b8586f7edc56c4c8548542bd0154164;hpb=a6057323869de5b323d1c75e678b6a0fe0e8addd;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 08b62003..46bb6961 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -349,6 +349,7 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no) p->port_no = port_no; p->dp = dp; p->dev = dev; + atomic_set(&p->sflow_pool, 0); if (!is_dp_dev(dev)) rcu_assign_pointer(dev->br_port, p); else { @@ -419,6 +420,7 @@ got_port_no: if (err) goto out_put; + set_dp_devs_mtu(dp, dev); dp_sysfs_add_if(dp->ports[port_no]); err = __put_user(port_no, &port.port); @@ -575,9 +577,10 @@ static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) #endif #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID) -/* This code is copied verbatim from net/dev/core.c in Xen's - * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644. We can't call those functions - * directly because they aren't exported. */ +/* This code is based on a skb_checksum_setup from net/dev/core.c from a + * combination of Lenny's 2.6.26 Xen kernel and Xen's + * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644. We can't call this function + * directly because it isn't exported in all versions. */ static int skb_pull_up_to(struct sk_buff *skb, void *ptr) { if (ptr < (void *)skb->tail) @@ -592,38 +595,59 @@ static int skb_pull_up_to(struct sk_buff *skb, void *ptr) int vswitch_skb_checksum_setup(struct sk_buff *skb) { - if (skb->proto_csum_blank) { - if (skb->protocol != htons(ETH_P_IP)) - goto out; - if (!skb_pull_up_to(skb, skb->nh.iph + 1)) - goto out; - skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - skb->csum = offsetof(struct tcphdr, check); - break; - case IPPROTO_UDP: - skb->csum = offsetof(struct udphdr, check); - break; - default: - if (net_ratelimit()) - printk(KERN_ERR "Attempting to checksum a non-" - "TCP/UDP packet, dropping a protocol" - " %d packet", skb->nh.iph->protocol); - goto out; - } - if (!skb_pull_up_to(skb, skb->h.raw + skb->csum + 2)) - goto out; - skb->ip_summed = CHECKSUM_HW; - skb->proto_csum_blank = 0; + struct iphdr *iph; + unsigned char *th; + int err = -EPROTO; + __u16 csum_start, csum_offset; + + if (!skb->proto_csum_blank) + return 0; + + if (skb->protocol != htons(ETH_P_IP)) + goto out; + + if (!skb_pull_up_to(skb, skb_network_header(skb) + 1)) + goto out; + + iph = ip_hdr(skb); + th = skb_network_header(skb) + 4 * iph->ihl; + + csum_start = th - skb->head; + switch (iph->protocol) { + case IPPROTO_TCP: + csum_offset = offsetof(struct tcphdr, check); + break; + case IPPROTO_UDP: + csum_offset = offsetof(struct udphdr, check); + break; + default: + if (net_ratelimit()) + printk(KERN_ERR "Attempting to checksum a non-" + "TCP/UDP packet, dropping a protocol" + " %d packet", iph->protocol); + goto out; } - return 0; + + if (!skb_pull_up_to(skb, th + csum_offset + 2)) + goto out; + + skb->ip_summed = CHECKSUM_PARTIAL; + skb->proto_csum_blank = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + skb->csum_start = csum_start; + skb->csum_offset = csum_offset; +#else + skb_set_transport_header(skb, csum_start - skb_headroom(skb)); + skb->csum = csum_offset; +#endif + + err = 0; + out: - return -EPROTO; + return err; } -#else -int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; } -#endif /* CONFIG_XEN && linux == 2.6.18 */ +#endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */ /* Types of checksums that we can receive (these all refer to L4 checksums): * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full @@ -646,7 +670,7 @@ int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; } * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was * generated locally by a Xen DomU and has a partial checksum. If it is * handled on this machine (Dom0 or DomU), then the checksum will not be - * computed. If it goes off box, the checksum in the packet needs to + * computed. If it goes off box, the checksum in the packet needs to be * completed. Calling skb_checksum_setup converts this to CHECKSUM_HW * (CHECKSUM_PARTIAL) so that the checksum can be completed. In later * kernels, this combination is replaced with CHECKSUM_PARTIAL. @@ -771,8 +795,7 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, int err; WARN_ON_ONCE(skb_shared(skb)); - BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR); - + BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR && queue_no != _ODPL_SFLOW_NR); queue = &dp->queues[queue_no]; err = -ENOBUFS; if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN) @@ -1295,6 +1318,29 @@ int dp_min_mtu(const struct datapath *dp) return mtu ? mtu : ETH_DATA_LEN; } +/* Sets the MTU of all datapath devices to the minimum of the ports. 'dev' + * is the device whose MTU may have changed. Must be called with RTNL lock + * and dp_mutex. */ +void set_dp_devs_mtu(const struct datapath *dp, struct net_device *dev) +{ + struct net_bridge_port *p; + int mtu; + + ASSERT_RTNL(); + + if (is_dp_dev(dev)) + return; + + mtu = dp_min_mtu(dp); + + list_for_each_entry_rcu (p, &dp->port_list, node) { + struct net_device *br_dev = p->dev; + + if (is_dp_dev(br_dev)) + dev_set_mtu(br_dev, mtu); + } +} + static int put_port(const struct net_bridge_port *p, struct odp_port __user *uop) { @@ -1451,6 +1497,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, int dp_idx = iminor(f->f_dentry->d_inode); struct datapath *dp; int drop_frags, listeners, port_no; + unsigned int sflow_probability; int err; /* Handle commands with special locking requirements up front. */ @@ -1514,6 +1561,16 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, set_listen_mask(f, listeners); break; + case ODP_GET_SFLOW_PROBABILITY: + err = put_user(dp->sflow_probability, (unsigned int __user *)argp); + break; + + case ODP_SET_SFLOW_PROBABILITY: + err = get_user(sflow_probability, (unsigned int __user *)argp); + if (!err) + dp->sflow_probability = sflow_probability; + break; + case ODP_PORT_QUERY: err = query_port(dp, (struct odp_port __user *)argp); break;