X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=b8ef104aa63659158aa9c982c3cb7cbc11f09d92;hb=411baaacb8672cd9b231328b77a5f1c8a11aad9c;hp=427391ad81038f1467102da5880336d211e4307f;hpb=39fb08818bbd9c438dbf23caa89937c663451b5a;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 427391ad..b8ef104a 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -56,9 +56,7 @@ int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); EXPORT_SYMBOL(dp_ioctl_hook); /* Datapaths. Protected on the read side by rcu_read_lock, on the write side - * by dp_mutex. dp_mutex is almost completely redundant with genl_mutex - * maintained by the Generic Netlink code, but the timeout path needs mutual - * exclusion too. + * by dp_mutex. * * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL * lock first. @@ -627,13 +625,93 @@ out: int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; } #endif /* CONFIG_XEN && linux == 2.6.18 */ +/* Append each packet in 'skb' list to 'queue'. There will be only one packet + * unless we broke up a GSO packet. */ +static int +queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue, + int queue_no, u32 arg) +{ + struct sk_buff *nskb; + int port_no; + int err; + + port_no = ODPP_LOCAL; + if (skb->dev) { + if (skb->dev->br_port) + port_no = skb->dev->br_port->port_no; + else if (is_dp_dev(skb->dev)) + port_no = dp_dev_priv(skb->dev)->port_no; + } + + do { + struct odp_msg *header; + + nskb = skb->next; + skb->next = NULL; + + /* If a checksum-deferred packet is forwarded to the + * controller, correct the pointers and checksum. This happens + * on a regular basis only on Xen, on which VMs can pass up + * packets that do not have their checksum computed. + */ + err = vswitch_skb_checksum_setup(skb); + if (err) + goto err_kfree_skbs; +#ifndef CHECKSUM_HW + if (skb->ip_summed == CHECKSUM_PARTIAL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + /* Until 2.6.22, the start of the transport header was + * also the start of data to be checksummed. Linux + * 2.6.22 introduced the csum_start field for this + * purpose, but we should point the transport header to + * it anyway for backward compatibility, as + * dev_queue_xmit() does even in 2.6.28. */ + skb_set_transport_header(skb, skb->csum_start - + skb_headroom(skb)); +#endif + err = skb_checksum_help(skb); + if (err) + goto err_kfree_skbs; + } +#else + if (skb->ip_summed == CHECKSUM_HW) { + err = skb_checksum_help(skb, 0); + if (err) + goto err_kfree_skbs; + } +#endif + + err = skb_cow(skb, sizeof *header); + if (err) + goto err_kfree_skbs; + + header = (struct odp_msg*)__skb_push(skb, sizeof *header); + header->type = queue_no; + header->length = skb->len; + header->port = port_no; + header->reserved = 0; + header->arg = arg; + skb_queue_tail(queue, skb); + + skb = nskb; + } while (skb); + return 0; + +err_kfree_skbs: + kfree_skb(skb); + while ((skb = nskb) != NULL) { + nskb = skb->next; + kfree_skb(skb); + } + return err; +} + int dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, u32 arg) { struct dp_stats_percpu *stats; struct sk_buff_head *queue; - int port_no; int err; WARN_ON_ONCE(skb_shared(skb)); @@ -644,37 +722,6 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN) goto err_kfree_skb; - /* If a checksum-deferred packet is forwarded to the controller, - * correct the pointers and checksum. This happens on a regular basis - * only on Xen, on which VMs can pass up packets that do not have their - * checksum computed. - */ - err = vswitch_skb_checksum_setup(skb); - if (err) - goto err_kfree_skb; -#ifndef CHECKSUM_HW - if (skb->ip_summed == CHECKSUM_PARTIAL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) - /* Until 2.6.22, the start of the transport header was also the - * start of data to be checksummed. Linux 2.6.22 introduced - * the csum_start field for this purpose, but we should point - * the transport header to it anyway for backward - * compatibility, as dev_queue_xmit() does even in 2.6.28. */ - skb_set_transport_header(skb, skb->csum_start - - skb_headroom(skb)); -#endif - err = skb_checksum_help(skb); - if (err) - goto err_kfree_skb; - } -#else - if (skb->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(skb, 0); - if (err) - goto err_kfree_skb; - } -#endif - /* Break apart GSO packets into their component pieces. Otherwise * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */ if (skb_is_gso(skb)) { @@ -692,45 +739,9 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, } } - /* Figure out port number. */ - port_no = ODPP_LOCAL; - if (skb->dev) { - if (skb->dev->br_port) - port_no = skb->dev->br_port->port_no; - else if (is_dp_dev(skb->dev)) - port_no = dp_dev_priv(skb->dev)->port_no; - } - - /* Append each packet to queue. There will be only one packet unless - * we broke up a GSO packet above. */ - do { - struct odp_msg *header; - struct sk_buff *nskb = skb->next; - skb->next = NULL; - - err = skb_cow(skb, sizeof *header); - if (err) { - while (nskb) { - kfree_skb(skb); - skb = nskb; - nskb = skb->next; - } - goto err_kfree_skb; - } - - header = (struct odp_msg*)__skb_push(skb, sizeof *header); - header->type = queue_no; - header->length = skb->len; - header->port = port_no; - header->reserved = 0; - header->arg = arg; - skb_queue_tail(queue, skb); - - skb = nskb; - } while (skb); - + err = queue_control_packets(skb, queue, queue_no, arg); wake_up_interruptible(&dp->waitqueue); - return 0; + return err; err_kfree_skb: kfree_skb(skb); @@ -1571,6 +1582,8 @@ struct file_operations openvswitch_fops = { }; static int major; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) static struct llc_sap *dp_stp_sap; static int dp_stp_rcv(struct sk_buff *skb, struct net_device *dev, @@ -1583,12 +1596,8 @@ static int dp_stp_rcv(struct sk_buff *skb, struct net_device *dev, return 0; } -static int __init dp_init(void) +static int dp_avoid_bridge_init(void) { - int err; - - printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); - /* Register to receive STP packets because the bridge module also * attempts to do so. Since there can only be a single listener for a * given protocol, this provides mutual exclusion against the bridge @@ -1599,6 +1608,43 @@ static int __init dp_init(void) printk(KERN_ERR "openvswitch: can't register sap for STP (probably the bridge module is loaded)\n"); return -EADDRINUSE; } + return 0; +} + +static void dp_avoid_bridge_exit(void) +{ + llc_sap_put(dp_stp_sap); +} +#else /* Linux 2.6.27 or later. */ +static int dp_avoid_bridge_init(void) +{ + /* Linux 2.6.27 introduces a way for multiple clients to register for + * STP packets, which interferes with what we try to do above. + * Instead, just check whether there's a bridge hook defined. This is + * not as safe--the bridge module is willing to load over the top of + * us--but it provides a little bit of protection. */ + if (br_handle_frame_hook) { + printk(KERN_ERR "openvswitch: bridge module is loaded, cannot load over it\n"); + return -EADDRINUSE; + } + return 0; +} + +static void dp_avoid_bridge_exit(void) +{ + /* Nothing to do. */ +} +#endif /* Linux 2.6.27 or later */ + +static int __init dp_init(void) +{ + int err; + + printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); + + err = dp_avoid_bridge_init(); + if (err) + return err; err = flow_init(); if (err) @@ -1633,7 +1679,7 @@ static void dp_cleanup(void) unregister_netdevice_notifier(&dp_device_notifier); flow_exit(); br_handle_frame_hook = NULL; - llc_sap_put(dp_stp_sap); + dp_avoid_bridge_exit(); } module_init(dp_init);