X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fvport.c;h=fdbf522e8d73d4e92ca6b1b22cfe63c0edd1335c;hb=b279fccf5bd8c5addfb8e73b04103405b6a8237e;hp=5437a9756b74285ce5a650e7a95fa58be571b872;hpb=fceb2a5bb2063023777fc75c68a2670b5169fa13;p=openvswitch diff --git a/datapath/vport.c b/datapath/vport.c index 5437a975..fdbf522e 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -6,6 +6,8 @@ * kernel, by Linus Torvalds and others. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -16,17 +18,21 @@ #include #include #include +#include #include "vport.h" #include "vport-internal_dev.h" /* List of statically compiled vport implementations. Don't forget to also * add yours to the list at the bottom of vport.h. */ -static struct vport_ops *base_vport_ops_list[] = { +static const struct vport_ops *base_vport_ops_list[] = { &netdev_vport_ops, &internal_vport_ops, &patch_vport_ops, &gre_vport_ops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + &capwap_vport_ops, +#endif }; static const struct vport_ops **vport_ops_list; @@ -35,17 +41,6 @@ static int n_vport_types; static struct hlist_head *dev_table; #define VPORT_HASH_BUCKETS 1024 -/* We limit the number of times that we pass through vport_send() to - * avoid blowing out the stack in the event that we have a loop. There is - * a separate counter for each CPU for both interrupt and non-interrupt - * context in order to keep the limit deterministic for a given packet. */ -struct percpu_loop_counter { - int count[2]; -}; - -static struct percpu_loop_counter *vport_loop_counter; -#define VPORT_MAX_LOOPS 5 - /* Both RTNL lock and vport_mutex need to be held when updating dev_table. * * If you use vport_locate and then perform some operations, you need to hold @@ -83,13 +78,14 @@ void vport_unlock(void) mutex_unlock(&vport_mutex); } -#define ASSERT_VPORT() do { \ - if (unlikely(!mutex_is_locked(&vport_mutex))) { \ - printk(KERN_ERR "openvswitch: vport lock not held at %s (%d)\n", \ - __FILE__, __LINE__); \ - dump_stack(); \ - } \ -} while(0) +#define ASSERT_VPORT() \ +do { \ + if (unlikely(!mutex_is_locked(&vport_mutex))) { \ + pr_err("vport lock not held at %s (%d)\n", \ + __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) /** * vport_init - initialize vport subsystem @@ -116,14 +112,8 @@ int vport_init(void) goto error_dev_table; } - vport_loop_counter = alloc_percpu(struct percpu_loop_counter); - if (!vport_loop_counter) { - err = -ENOMEM; - goto error_ops_list; - } - for (i = 0; i < ARRAY_SIZE(base_vport_ops_list); i++) { - struct vport_ops *new_ops = base_vport_ops_list[i]; + const struct vport_ops *new_ops = base_vport_ops_list[i]; if (new_ops->init) err = new_ops->init(); @@ -140,8 +130,6 @@ int vport_init(void) return 0; -error_ops_list: - kfree(vport_ops_list); error_dev_table: kfree(dev_table); error: @@ -185,7 +173,6 @@ void vport_exit(void) vport_ops_list[i]->exit(); } - free_percpu(vport_loop_counter); kfree(vport_ops_list); kfree(dev_table); } @@ -632,7 +619,7 @@ struct vport *vport_locate(const char *name) struct hlist_node *node; if (unlikely(!mutex_is_locked(&vport_mutex) && !rtnl_is_locked())) { - printk(KERN_ERR "openvswitch: neither RTNL nor vport lock held in vport_locate\n"); + pr_err("neither RTNL nor vport lock held in vport_locate\n"); dump_stack(); } @@ -807,9 +794,6 @@ int vport_attach(struct vport *vport, struct dp_port *dp_port) { ASSERT_RTNL(); - if (dp_port->vport) - return -EBUSY; - if (vport_get_dp_port(vport)) return -EBUSY; @@ -821,7 +805,6 @@ int vport_attach(struct vport *vport, struct dp_port *dp_port) return err; } - dp_port->vport = vport; rcu_assign_pointer(vport->dp_port, dp_port); return 0; @@ -845,7 +828,6 @@ int vport_detach(struct vport *vport) if (!dp_port) return -EINVAL; - dp_port->vport = NULL; rcu_assign_pointer(vport->dp_port, NULL); if (vport->ops->detach) @@ -922,13 +904,13 @@ int vport_set_addr(struct vport *vport, const unsigned char *addr) * support setting the stats, in which case the result will always be * -EOPNOTSUPP. RTNL lock must be held. */ -int vport_set_stats(struct vport *vport, struct odp_vport_stats *stats) +int vport_set_stats(struct vport *vport, struct rtnl_link_stats64 *stats) { ASSERT_RTNL(); if (vport->ops->flags & VPORT_F_GEN_STATS) { spin_lock_bh(&vport->stats_lock); - memcpy(&vport->offset_stats, stats, sizeof(struct odp_vport_stats)); + vport->offset_stats = *stats; spin_unlock_bh(&vport->stats_lock); return 0; @@ -1016,10 +998,10 @@ struct kobject *vport_get_kobj(const struct vport *vport) * * Retrieves transmit, receive, and error stats for the given device. */ -int vport_get_stats(struct vport *vport, struct odp_vport_stats *stats) +int vport_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats) { - struct odp_vport_stats dev_stats; - struct odp_vport_stats *dev_statsp = NULL; + struct rtnl_link_stats64 dev_stats; + struct rtnl_link_stats64 *dev_statsp = NULL; int err; if (vport->ops->get_stats) { @@ -1048,41 +1030,57 @@ int vport_get_stats(struct vport *vport, struct odp_vport_stats *stats) spin_lock_bh(&vport->stats_lock); - memcpy(stats, &vport->offset_stats, sizeof(struct odp_vport_stats)); + *stats = vport->offset_stats; - stats->rx_errors += vport->err_stats.rx_errors - + vport->err_stats.rx_frame_err - + vport->err_stats.rx_over_err - + vport->err_stats.rx_crc_err; + stats->rx_errors += vport->err_stats.rx_errors; stats->tx_errors += vport->err_stats.tx_errors; stats->tx_dropped += vport->err_stats.tx_dropped; stats->rx_dropped += vport->err_stats.rx_dropped; - stats->rx_over_err += vport->err_stats.rx_over_err; - stats->rx_crc_err += vport->err_stats.rx_crc_err; - stats->rx_frame_err += vport->err_stats.rx_frame_err; - stats->collisions += vport->err_stats.collisions; spin_unlock_bh(&vport->stats_lock); if (dev_statsp) { - stats->rx_errors += dev_statsp->rx_errors; - stats->tx_errors += dev_statsp->tx_errors; - stats->rx_dropped += dev_statsp->rx_dropped; - stats->tx_dropped += dev_statsp->tx_dropped; - stats->rx_over_err += dev_statsp->rx_over_err; - stats->rx_crc_err += dev_statsp->rx_crc_err; - stats->rx_frame_err += dev_statsp->rx_frame_err; - stats->collisions += dev_statsp->collisions; + stats->rx_packets += dev_statsp->rx_packets; + stats->tx_packets += dev_statsp->tx_packets; + stats->rx_bytes += dev_statsp->rx_bytes; + stats->tx_bytes += dev_statsp->tx_bytes; + stats->rx_errors += dev_statsp->rx_errors; + stats->tx_errors += dev_statsp->tx_errors; + stats->rx_dropped += dev_statsp->rx_dropped; + stats->tx_dropped += dev_statsp->tx_dropped; + stats->multicast += dev_statsp->multicast; + stats->collisions += dev_statsp->collisions; + stats->rx_length_errors += dev_statsp->rx_length_errors; + stats->rx_over_errors += dev_statsp->rx_over_errors; + stats->rx_crc_errors += dev_statsp->rx_crc_errors; + stats->rx_frame_errors += dev_statsp->rx_frame_errors; + stats->rx_fifo_errors += dev_statsp->rx_fifo_errors; + stats->rx_missed_errors += dev_statsp->rx_missed_errors; + stats->tx_aborted_errors += dev_statsp->tx_aborted_errors; + stats->tx_carrier_errors += dev_statsp->tx_carrier_errors; + stats->tx_fifo_errors += dev_statsp->tx_fifo_errors; + stats->tx_heartbeat_errors += dev_statsp->tx_heartbeat_errors; + stats->tx_window_errors += dev_statsp->tx_window_errors; + stats->rx_compressed += dev_statsp->rx_compressed; + stats->tx_compressed += dev_statsp->tx_compressed; } for_each_possible_cpu(i) { const struct vport_percpu_stats *percpu_stats; + struct vport_percpu_stats local_stats; + unsigned seqcount; percpu_stats = per_cpu_ptr(vport->percpu_stats, i); - stats->rx_bytes += percpu_stats->rx_bytes; - stats->rx_packets += percpu_stats->rx_packets; - stats->tx_bytes += percpu_stats->tx_bytes; - stats->tx_packets += percpu_stats->tx_packets; + + do { + seqcount = read_seqcount_begin(&percpu_stats->seqlock); + local_stats = *percpu_stats; + } while (read_seqcount_retry(&percpu_stats->seqlock, seqcount)); + + stats->rx_bytes += local_stats.rx_bytes; + stats->rx_packets += local_stats.rx_packets; + stats->tx_bytes += local_stats.tx_bytes; + stats->tx_packets += local_stats.tx_packets; } err = 0; @@ -1217,14 +1215,19 @@ void vport_receive(struct vport *vport, struct sk_buff *skb) struct vport_percpu_stats *stats; local_bh_disable(); - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); + + write_seqcount_begin(&stats->seqlock); stats->rx_packets++; stats->rx_bytes += skb->len; + write_seqcount_end(&stats->seqlock); local_bh_enable(); } + if (!(vport->ops->flags & VPORT_F_FLOW)) + OVS_CB(skb)->flow = NULL; + if (!(vport->ops->flags & VPORT_F_TUN_ID)) OVS_CB(skb)->tun_id = 0; @@ -1252,25 +1255,15 @@ static inline unsigned packet_length(const struct sk_buff *skb) */ int vport_send(struct vport *vport, struct sk_buff *skb) { - int *loop_count; int mtu; int sent; - loop_count = &per_cpu_ptr(vport_loop_counter, get_cpu())->count[!!in_interrupt()]; - (*loop_count)++; - - if (unlikely(*loop_count > VPORT_MAX_LOOPS)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: dropping packet that has looped more than %d times\n", - dp_name(vport_get_dp_port(vport)->dp), VPORT_MAX_LOOPS); - goto error; - } - mtu = vport_get_mtu(vport); if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { if (net_ratelimit()) - printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n", - dp_name(vport_get_dp_port(vport)->dp), packet_length(skb), mtu); + pr_warn("%s: dropped over-mtu packet: %d > %d\n", + dp_name(vport_get_dp_port(vport)->dp), + packet_length(skb), mtu); goto error; } @@ -1280,25 +1273,22 @@ int vport_send(struct vport *vport, struct sk_buff *skb) struct vport_percpu_stats *stats; local_bh_disable(); - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); + + write_seqcount_begin(&stats->seqlock); stats->tx_packets++; stats->tx_bytes += sent; + write_seqcount_end(&stats->seqlock); local_bh_enable(); } - goto out; + return sent; error: - sent = 0; kfree_skb(skb); vport_record_error(vport, VPORT_E_TX_DROPPED); -out: - (*loop_count)--; - put_cpu(); - - return sent; + return 0; } /** @@ -1325,18 +1315,6 @@ void vport_record_error(struct vport *vport, enum vport_err_type err_type) vport->err_stats.rx_errors++; break; - case VPORT_E_RX_FRAME: - vport->err_stats.rx_frame_err++; - break; - - case VPORT_E_RX_OVER: - vport->err_stats.rx_over_err++; - break; - - case VPORT_E_RX_CRC: - vport->err_stats.rx_crc_err++; - break; - case VPORT_E_TX_DROPPED: vport->err_stats.tx_dropped++; break; @@ -1344,10 +1322,6 @@ void vport_record_error(struct vport *vport, enum vport_err_type err_type) case VPORT_E_TX_ERROR: vport->err_stats.tx_errors++; break; - - case VPORT_E_COLLISION: - vport->err_stats.collisions++; - break; }; spin_unlock_bh(&vport->stats_lock);