X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=b6aefe892156fb3cbc887bd3d897c78140574bb4;hb=3612b72c3639f22b33786c2fac3fb291ff9f6061;hp=08b620036b8586f7edc56c4c8548542bd0154164;hpb=a6057323869de5b323d1c75e678b6a0fe0e8addd;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 08b62003..b6aefe89 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -71,6 +71,7 @@ static DEFINE_MUTEX(dp_mutex); #define MAINT_SLEEP_MSECS 1000 static int new_nbp(struct datapath *, struct net_device *, int port_no); +static void compute_ip_summed(struct sk_buff *skb); /* Must be called with rcu_read_lock or dp_mutex. */ struct datapath *get_dp(int dp_idx) @@ -81,7 +82,7 @@ struct datapath *get_dp(int dp_idx) } EXPORT_SYMBOL_GPL(get_dp); -struct datapath *get_dp_locked(int dp_idx) +static struct datapath *get_dp_locked(int dp_idx) { struct datapath *dp; @@ -176,7 +177,7 @@ static void release_dp(struct kobject *kobj) kfree(dp); } -struct kobj_type dp_ktype = { +static struct kobj_type dp_ktype = { .release = release_dp }; @@ -325,7 +326,7 @@ static void release_nbp(struct kobject *kobj) kfree(p); } -struct kobj_type brport_ktype = { +static struct kobj_type brport_ktype = { #ifdef CONFIG_SYSFS .sysfs_ops = &brport_sysfs_ops, #endif @@ -349,6 +350,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,9 +421,10 @@ 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); + err = __put_user(port_no, &portp->port); out_put: dev_put(dev); @@ -527,6 +530,8 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p) WARN_ON_ONCE(skb_shared(skb)); + compute_ip_summed(skb); + /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */ stats = percpu_ptr(dp->stats_percpu, smp_processor_id()); @@ -575,9 +580,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 +598,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) + sizeof(struct iphdr))) + 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 +673,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. @@ -672,11 +699,33 @@ int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; } * skb_forward_csum(). It is slightly different because we are only concerned * with bridging and not other types of forwarding and can get away with * slightly more optimal behavior.*/ +static void +compute_ip_summed(struct sk_buff *skb) +{ + OVS_CB(skb)->ip_summed = skb->ip_summed; + +#ifdef CHECKSUM_HW + /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE. + * However, we should only get CHECKSUM_PARTIAL packets from Xen, which + * uses some special fields to represent this (see below). Since we + * can only make one type work, pick the one that actually happens in + * practice. */ + if (skb->ip_summed == CHECKSUM_HW) + OVS_CB(skb)->ip_summed = CSUM_COMPLETE; +#endif +#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID) + /* Xen has a special way of representing CHECKSUM_PARTIAL on older + * kernels. */ + if (skb->proto_csum_blank) + OVS_CB(skb)->ip_summed = CSUM_PARTIAL; +#endif +} + void forward_ip_summed(struct sk_buff *skb) { #ifdef CHECKSUM_HW - if (skb->ip_summed == CHECKSUM_HW) + if (OVS_CB(skb)->ip_summed == CSUM_COMPLETE) skb->ip_summed = CHECKSUM_NONE; #endif } @@ -771,8 +820,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) @@ -917,7 +965,7 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp) error = -EFAULT; if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put))) goto error; - uf.flow.key.reserved = 0; + memset(uf.flow.key.reserved, 0, sizeof uf.flow.key.reserved); table = rcu_dereference(dp->table); flow = dp_table_lookup(table, &uf.flow.key); @@ -1062,7 +1110,7 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) error = -EFAULT; if (copy_from_user(&uf, ufp, sizeof uf)) goto error; - uf.key.reserved = 0; + memset(uf.key.reserved, 0, sizeof uf.key.reserved); flow = dp_table_lookup(table, &uf.key); error = -ENOENT; @@ -1098,7 +1146,7 @@ static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) if (__copy_from_user(&uf, ufp, sizeof uf)) return -EFAULT; - uf.key.reserved = 0; + memset(uf.key.reserved, 0, sizeof uf.key.reserved); flow = dp_table_lookup(table, &uf.key); if (!flow) @@ -1295,6 +1343,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 +1522,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 +1586,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;