~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to datapath/vport-netdev.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
#define vlan_tso true
46
46
#endif
47
47
 
48
 
#ifdef HAVE_RHEL_OVS_HOOK
49
 
static atomic_t nr_bridges = ATOMIC_INIT(0);
50
 
 
51
 
extern struct sk_buff *(*openvswitch_handle_frame_hook)(struct sk_buff *skb);
52
 
#endif
53
 
 
54
48
static void netdev_port_receive(struct vport *vport, struct sk_buff *skb);
55
49
 
56
50
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
117
111
static int netdev_init(void) { return 0; }
118
112
static void netdev_exit(void) { }
119
113
#else
120
 
static int netdev_init(void)
 
114
static int port_count;
 
115
 
 
116
static void netdev_init(void)
121
117
{
 
118
        port_count++;
 
119
        if (port_count > 1)
 
120
                return;
 
121
 
122
122
        /* Hook into callback used by the bridge to intercept packets.
123
123
         * Parasites we are. */
124
124
        br_handle_frame_hook = netdev_frame_hook;
125
125
 
126
 
        return 0;
 
126
        return;
127
127
}
128
128
 
129
129
static void netdev_exit(void)
130
130
{
 
131
        port_count--;
 
132
        if (port_count > 0)
 
133
                return;
 
134
 
131
135
        br_handle_frame_hook = NULL;
132
136
}
133
137
#endif
160
164
                goto error_put;
161
165
        }
162
166
 
163
 
#ifdef HAVE_RHEL_OVS_HOOK
164
 
        rcu_assign_pointer(netdev_vport->dev->ax25_ptr, vport);
165
 
        atomic_inc(&nr_bridges);
166
 
        rcu_assign_pointer(openvswitch_handle_frame_hook, netdev_frame_hook);
167
 
#else
 
167
        rtnl_lock();
168
168
        err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook,
169
169
                                         vport);
170
170
        if (err)
171
 
                goto error_put;
172
 
#endif
 
171
                goto error_unlock;
173
172
 
174
173
        dev_set_promiscuity(netdev_vport->dev, 1);
175
174
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
176
175
        dev_disable_lro(netdev_vport->dev);
177
176
#endif
178
177
        netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
 
178
        rtnl_unlock();
179
179
 
 
180
        netdev_init();
180
181
        return vport;
181
182
 
 
183
error_unlock:
 
184
        rtnl_unlock();
182
185
error_put:
183
186
        dev_put(netdev_vport->dev);
184
187
error_free_vport:
192
195
        struct netdev_vport *netdev_vport = container_of(rcu,
193
196
                                        struct netdev_vport, rcu);
194
197
 
195
 
#ifdef HAVE_RHEL_OVS_HOOK
196
 
        rcu_assign_pointer(netdev_vport->dev->ax25_ptr, NULL);
197
 
 
198
 
        if (atomic_dec_and_test(&nr_bridges))
199
 
                rcu_assign_pointer(openvswitch_handle_frame_hook, NULL);
200
 
#endif
201
198
        dev_put(netdev_vport->dev);
202
199
        ovs_vport_free(vport_from_priv(netdev_vport));
203
200
}
206
203
{
207
204
        struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
208
205
 
 
206
        netdev_exit();
 
207
        rtnl_lock();
209
208
        netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
210
209
        netdev_rx_handler_unregister(netdev_vport->dev);
211
210
        dev_set_promiscuity(netdev_vport->dev, -1);
 
211
        rtnl_unlock();
212
212
 
213
213
        call_rcu(&netdev_vport->rcu, free_port_rcu);
214
214
}
219
219
        return netdev_vport->dev->name;
220
220
}
221
221
 
222
 
int ovs_netdev_get_ifindex(const struct vport *vport)
223
 
{
224
 
        const struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
225
 
        return netdev_vport->dev->ifindex;
226
 
}
227
 
 
228
222
/* Must be called with rcu_read_lock. */
229
223
static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
230
224
{
242
236
        if (unlikely(!skb))
243
237
                return;
244
238
 
 
239
        if (unlikely(compute_ip_summed(skb, false)))
 
240
                goto error;
 
241
 
245
242
        skb_push(skb, ETH_HLEN);
246
 
 
247
 
        if (unlikely(compute_ip_summed(skb, false)))
248
 
                goto error;
 
243
        ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
249
244
 
250
245
        vlan_copy_skb_tci(skb);
251
246
 
252
 
        ovs_vport_receive(vport, skb);
 
247
        ovs_vport_receive(vport, skb, NULL);
253
248
        return;
254
249
 
255
250
error:
289
284
                net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
290
285
                                     netdev_vport->dev->name,
291
286
                                     packet_length(skb), mtu);
292
 
                goto error;
 
287
                goto drop;
293
288
        }
294
289
 
295
290
        skb->dev = netdev_vport->dev;
310
305
                        nskb = skb_gso_segment(skb, features);
311
306
                        if (!nskb) {
312
307
                                if (unlikely(skb_cloned(skb) &&
313
 
                                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) {
314
 
                                        kfree_skb(skb);
315
 
                                        return 0;
316
 
                                }
 
308
                                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 
309
                                        goto drop;
317
310
 
318
311
                                skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY;
319
312
                                goto tag;
320
313
                        }
321
314
 
322
 
                        if (IS_ERR(nskb)) {
323
 
                                kfree_skb(skb);
324
 
                                return 0;
325
 
                        }
 
315
                        if (IS_ERR(nskb))
 
316
                                goto drop;
326
317
                        consume_skb(skb);
327
318
                        skb = nskb;
328
319
 
356
347
 
357
348
        return len;
358
349
 
359
 
error:
 
350
drop:
360
351
        kfree_skb(skb);
361
 
        ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
362
352
        return 0;
363
353
}
364
354
 
386
376
 
387
377
const struct vport_ops ovs_netdev_vport_ops = {
388
378
        .type           = OVS_VPORT_TYPE_NETDEV,
389
 
        .flags          = VPORT_F_REQUIRED,
390
 
        .init           = netdev_init,
391
 
        .exit           = netdev_exit,
392
379
        .create         = netdev_create,
393
380
        .destroy        = netdev_destroy,
394
381
        .get_name       = ovs_netdev_get_name,
395
 
        .get_ifindex    = ovs_netdev_get_ifindex,
396
382
        .send           = netdev_send,
397
383
};
398
384