X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=6365f9474564dbac9c7be08d6c697a416bda155b;hb=7c88a5dc3ac1a034552bb94d42394bd325c1204e;hp=46bb6961cef5cbd51f5303b184e5e25790984ddc;hpb=7dab847a19503f537c57c2215748f0b50b94f51e;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 46bb6961..6365f947 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "openvswitch/datapath-protocol.h" @@ -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 @@ -358,6 +359,7 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no) * in dp_frame_hook(). In turn dp_frame_hook() can reject them * back to network stack, but that's a waste of time. */ } + dev_disable_lro(dev); rcu_assign_pointer(dp->ports[port_no], p); list_add_rcu(&p->node, &dp->port_list); dp->n_ports++; @@ -423,7 +425,7 @@ got_port_no: 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); @@ -505,6 +507,11 @@ out: static void do_port_input(struct net_bridge_port *p, struct sk_buff *skb) { + /* LRO isn't suitable for bridging. We turn it off but make sure + * that it wasn't reactivated. */ + if (skb_warn_if_lro(skb)) + return; + /* Make our own copy of the packet. Otherwise we will mangle the * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). * (No one comes after us, since we tell handle_bridge() that we took @@ -529,6 +536,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, false); + /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */ stats = percpu_ptr(dp->stats_percpu, smp_processor_id()); @@ -606,7 +615,7 @@ int vswitch_skb_checksum_setup(struct sk_buff *skb) if (skb->protocol != htons(ETH_P_IP)) goto out; - if (!skb_pull_up_to(skb, skb_network_header(skb) + 1)) + if (!skb_pull_up_to(skb, skb_network_header(skb) + sizeof(struct iphdr))) goto out; iph = ip_hdr(skb); @@ -696,11 +705,65 @@ out: * 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.*/ +void +compute_ip_summed(struct sk_buff *skb, bool xmit) +{ + /* For our convenience these defines change repeatedly between kernel + * versions, so we can't just copy them over... */ + switch (skb->ip_summed) { + case CHECKSUM_NONE: + OVS_CB(skb)->ip_summed = OVS_CSUM_NONE; + break; + case CHECKSUM_UNNECESSARY: + OVS_CB(skb)->ip_summed = OVS_CSUM_UNNECESSARY; + break; +#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. + * + * The one exception to this is if we are on the transmit path + * (basically after skb_checksum_setup() has been run) the type has + * already been converted, so we should stay with that. */ + case CHECKSUM_HW: + if (!xmit) + OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE; + else + OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL; + + break; +#else + case CHECKSUM_COMPLETE: + OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE; + break; + case CHECKSUM_PARTIAL: + OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL; + break; +#endif + default: + printk(KERN_ERR "openvswitch: unknown checksum type %d\n", + skb->ip_summed); + /* None seems the safest... */ + OVS_CB(skb)->ip_summed = OVS_CSUM_NONE; + } + +#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID) + /* Xen has a special way of representing CHECKSUM_PARTIAL on older + * kernels. It should not be set on the transmit path though. */ + if (skb->proto_csum_blank) + OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL; + + WARN_ON_ONCE(skb->proto_csum_blank && xmit); +#endif +} + void forward_ip_summed(struct sk_buff *skb) { #ifdef CHECKSUM_HW - if (skb->ip_summed == CHECKSUM_HW) + if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE) skb->ip_summed = CHECKSUM_NONE; #endif } @@ -868,6 +931,11 @@ static int validate_actions(const struct sw_flow_actions *actions) return -EINVAL; break; + case ODPAT_SET_NW_TOS: + if (a->nw_tos.nw_tos & INET_ECN_MASK) + return -EINVAL; + break; + default: if (a->type >= ODPAT_N_ACTIONS) return -EOPNOTSUPP; @@ -940,7 +1008,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); @@ -1085,7 +1153,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; @@ -1121,7 +1189,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)