/* called by execute_plums() to execute BPF program * or send it out of vport if destination plum_id is zero * It's called with rcu_read_lock. */ static void __bpf_forward(struct bpf_dp_context *ctx, u32 dest) { struct datapath *dp = ctx->dp; u32 plum_id = dest >> 16; u32 port_id = dest & 0xffff; struct plum *plum; struct vport *vport; struct ovs_key_ipv4_tunnel tun_key; plum = rcu_dereference(dp->plums[plum_id]); if (unlikely(!plum)) { kfree_skb(ctx->skb); return; } if (plum_id == 0) { if (ctx->context.tun_key.dst_ip) { tun_key.tun_id = cpu_to_be64(ctx->context.tun_key.tun_id); tun_key.ipv4_src = cpu_to_be32(ctx->context.tun_key.src_ip); tun_key.ipv4_dst = cpu_to_be32(ctx->context.tun_key.dst_ip); tun_key.ipv4_tos = ctx->context.tun_key.tos; tun_key.ipv4_ttl = ctx->context.tun_key.ttl; tun_key.tun_flags = TUNNEL_KEY; OVS_CB(ctx->skb)->tun_key = &tun_key; } else { OVS_CB(ctx->skb)->tun_key = NULL; } plum_update_stats(plum, port_id, ctx->skb, false); vport = ovs_vport_rcu(dp, port_id); if (unlikely(!vport)) { kfree_skb(ctx->skb); return; } /** begin_fixme **/ #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) offload_send(vport, ctx->skb); #else ovs_vport_send(vport, ctx->skb); #endif /** end_fixme **/ } else { ctx->context.port_id = port_id; ctx->context.plum_id = plum_id; BUG_ON(plum->run == NULL); plum_update_stats(plum, port_id, ctx->skb, true); /* execute BPF program */ plum->run(ctx); consume_skb(ctx->skb); } }
static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port) { struct vport *vport; if (unlikely(!skb)) return -ENOMEM; vport = rcu_dereference(dp->ports[out_port]); if (unlikely(!vport)) { kfree_skb(skb); return -ENODEV; } ovs_vport_send(vport, skb); return 0; }