Ejemplo n.º 1
0
/* Execute a list of actions against 'skb'. */
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
{
	struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
	struct loop_counter *loop;
	int error;
	struct ovs_key_ipv4_tunnel tun_key;

	/* Check whether we've looped too much. */
	loop = &__get_cpu_var(loop_counters);
	if (unlikely(++loop->count > MAX_LOOPS))
		loop->looping = true;
	if (unlikely(loop->looping)) {
		error = loop_suppress(dp, acts);
		kfree_skb(skb);
		goto out_loop;
	}

	OVS_CB(skb)->tun_key = NULL;
	error = do_execute_actions(dp, skb, acts->actions,
					 acts->actions_len, &tun_key, false);

	/* Check whether sub-actions looped too much. */
	if (unlikely(loop->looping))
		error = loop_suppress(dp, acts);

out_loop:
	/* Decrement loop counter. */
	if (!--loop->count)
		loop->looping = false;

	return error;
}
Ejemplo n.º 2
0
Archivo: vport.c Proyecto: JunoZhu/ovs
/**
 *	ovs_vport_receive - pass up received packet to the datapath for processing
 *
 * @vport: vport that received the packet
 * @skb: skb that was received
 * @tun_key: tunnel (if any) that carried packet
 *
 * Must be called with rcu_read_lock.  The packet cannot be shared and
 * skb->data should point to the Ethernet header.
 */
int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
		      const struct ip_tunnel_info *tun_info)
{
	struct sw_flow_key key;
	int error;

	OVS_CB(skb)->input_vport = vport;
	OVS_CB(skb)->mru = 0;
	OVS_CB(skb)->cutlen = 0;
	if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
		u32 mark;

		mark = skb->mark;
		skb_scrub_packet(skb, true);
		skb->mark = mark;
		tun_info = NULL;
	}

	ovs_skb_init_inner_protocol(skb);
	skb_clear_ovs_gso_cb(skb);
	/* Extract flow from 'skb' into 'key'. */
	error = ovs_flow_key_extract(tun_info, skb, &key);
	if (unlikely(error)) {
		kfree_skb(skb);
		return error;
	}
	ovs_dp_process_packet(skb, &key);
	return 0;
}
Ejemplo n.º 3
0
/* 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);
	}
}
Ejemplo n.º 4
0
/* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
 * value if 'skb' is freed.
 */
static int handle_fragments(struct net *net, struct sw_flow_key *key,
			    u16 zone, struct sk_buff *skb)
{
	struct ovs_skb_cb ovs_cb = *OVS_CB(skb);

	if (key->eth.type == htons(ETH_P_IP)) {
		enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
		int err;

		memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
		err = ip_defrag(skb, user);
		if (err)
			return err;

		ovs_cb.mru = IPCB(skb)->frag_max_size;
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
	} else if (key->eth.type == htons(ETH_P_IPV6)) {
		enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
		struct sk_buff *reasm;

		memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
		reasm = nf_ct_frag6_gather(skb, user);
		if (!reasm)
			return -EINPROGRESS;

		if (skb == reasm) {
			kfree_skb(skb);
			return -EINVAL;
		}

		/* Don't free 'skb' even though it is one of the original
		 * fragments, as we're going to morph it into the head.
		 */
		skb_get(skb);
		nf_ct_frag6_consume_orig(reasm);

		key->ip.proto = ipv6_hdr(reasm)->nexthdr;
		skb_morph(skb, reasm);
		skb->next = reasm->next;
		consume_skb(reasm);
		ovs_cb.mru = IP6CB(skb)->frag_max_size;
#endif
	} else {
		kfree_skb(skb);
		return -EPFNOSUPPORT;
	}

	key->ip.frag = OVS_FRAG_TYPE_NONE;
	skb_clear_hash(skb);
	skb->ignore_df = 1;
	*OVS_CB(skb) = ovs_cb;

	return 0;
}
Ejemplo n.º 5
0
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct ovs_key_ipv4_tunnel *tun_key;
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
	struct vxlan_metadata md = {0};
	struct rtable *rt;
	__be16 src_port;
	__be32 saddr;
	__be16 df;
	int err;
	u32 vxflags;

	if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
		err = -EINVAL;
		goto error;
	}

	tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;

	/* Route lookup */
	saddr = tun_key->ipv4_src;
	rt = find_route(ovs_dp_get_net(vport->dp),
			&saddr, tun_key->ipv4_dst,
			IPPROTO_UDP, tun_key->ipv4_tos,
			skb->mark);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		goto error;
	}

	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
	skb->ignore_df = 1;

	src_port = udp_flow_src_port(net, skb, 0, 0, true);
	md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
	md.gbp = vxlan_ext_gbp(skb);
	vxflags = vxlan_port->exts |
		      (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0);

	err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
			     saddr, tun_key->ipv4_dst,
			     tun_key->ipv4_tos,
			     tun_key->ipv4_ttl, df,
			     src_port, dst_port,
			     &md, false, vxflags);
	if (err < 0)
		ip_rt_put(rt);
	return err;
error:
	kfree_skb(skb);
	return err;
}
Ejemplo n.º 6
0
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
	struct ovs_key_ipv4_tunnel *tun_key;
	struct rtable *rt;
	struct flowi4 fl;
	__be16 src_port;
	__be16 df;
	int err;

	if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
		err = -EINVAL;
		goto error;
	}

	tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
	/* Route lookup */
	memset(&fl, 0, sizeof(fl));
	fl.daddr = tun_key->ipv4_dst;
	fl.saddr = tun_key->ipv4_src;
	fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos);
	fl.flowi4_mark = skb->mark;
	fl.flowi4_proto = IPPROTO_UDP;

	rt = ip_route_output_key(net, &fl);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		goto error;
	}

	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
		htons(IP_DF) : 0;

	skb->ignore_df = 1;

	src_port = udp_flow_src_port(net, skb, 0, 0, true);

	err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
			     fl.saddr, tun_key->ipv4_dst,
			     tun_key->ipv4_tos, tun_key->ipv4_ttl, df,
			     src_port, dst_port,
			     htonl(be64_to_cpu(tun_key->tun_id) << 8),
			     false);
	if (err < 0)
		ip_rt_put(rt);
	return err;
error:
	kfree_skb(skb);
	return err;
}
Ejemplo n.º 7
0
int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key)
{
	/* Extract metadata from packet. */

	memset(key, 0, sizeof(*key));
	if (OVS_CB(skb)->tun_key)
		memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));

	key->phy.priority = skb->priority;
	key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
	key->phy.skb_mark = skb->mark;

	return key_extract(skb, key);
}
Ejemplo n.º 8
0
/* Must be called with rcu_read_lock. */
void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
{
	struct datapath *dp = p->dp;
	struct sw_flow *flow;
	struct dp_stats_percpu *stats;
	u64 *stats_counter;
	int error;

	stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id());

	if (!OVS_CB(skb)->flow) {
		struct sw_flow_key key;
		int key_len;

		/* Extract flow from 'skb' into 'key'. */
		error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
		if (unlikely(error)) {
			kfree_skb(skb);
			return;
		}

		/* Look up flow. */
		flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table),
					   &key, key_len);
		if (unlikely(!flow)) {
			struct dp_upcall_info upcall;

			upcall.cmd = OVS_PACKET_CMD_MISS;
			upcall.key = &key;
			upcall.userdata = NULL;
			upcall.pid = p->upcall_pid;
			ovs_dp_upcall(dp, skb, &upcall);
			consume_skb(skb);
			stats_counter = &stats->n_missed;
			goto out;
		}

		OVS_CB(skb)->flow = flow;
	}

	stats_counter = &stats->n_hit;
	ovs_flow_used(OVS_CB(skb)->flow, skb);
	ovs_execute_actions(dp, skb);

out:
	/* Update datapath statistics. */
	u64_stats_update_begin(&stats->sync);
	(*stats_counter)++;
	u64_stats_update_end(&stats->sync);
}
Ejemplo n.º 9
0
static int execute_set_action(struct sk_buff *skb,
				 const struct nlattr *nested_attr,
				 struct ovs_key_ipv4_tunnel *tun_key)
{
	int err = 0;

	switch (nla_type(nested_attr)) {
	case OVS_KEY_ATTR_PRIORITY:
		skb->priority = nla_get_u32(nested_attr);
		break;

	case OVS_KEY_ATTR_TUN_ID:
		if (!OVS_CB(skb)->tun_key) {
			/* If tun_key is NULL for this skb, assign it to
			 * a value the caller passed in for action processing
			 * and output. This can disappear once we drop support
			 * for setting tun_id outside of tun_key.
			 */
			memset(tun_key, 0, sizeof(struct ovs_key_ipv4_tunnel));
			OVS_CB(skb)->tun_key = tun_key;
		}

		OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr);
		OVS_CB(skb)->tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY;
		break;

	case OVS_KEY_ATTR_IPV4_TUNNEL:
		OVS_CB(skb)->tun_key = nla_data(nested_attr);
		break;

	case OVS_KEY_ATTR_ETHERNET:
		err = set_eth_addr(skb, nla_data(nested_attr));
		break;

	case OVS_KEY_ATTR_IPV4:
		err = set_ipv4(skb, nla_data(nested_attr));
		break;

	case OVS_KEY_ATTR_TCP:
		err = set_tcp(skb, nla_data(nested_attr));
		break;

	case OVS_KEY_ATTR_UDP:
		err = set_udp(skb, nla_data(nested_attr));
		break;
	}

	return err;
}
Ejemplo n.º 10
0
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct ovs_key_ipv4_tunnel *tun_key;
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
	struct rtable *rt;
	__be16 src_port;
	__be32 saddr;
	__be16 df;
	int port_min;
	int port_max;
	int err;

	if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
		err = -EINVAL;
		goto error;
	}

	tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;

	/* Route lookup */
	saddr = tun_key->ipv4_src;
	rt = find_route(ovs_dp_get_net(vport->dp),
			&saddr, tun_key->ipv4_dst,
			IPPROTO_UDP, tun_key->ipv4_tos,
			skb->mark);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		goto error;
	}

	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
	skb->local_df = 1;

	inet_get_local_port_range(net, &port_min, &port_max);
	src_port = vxlan_src_port(port_min, port_max, skb);

	err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
			     saddr, tun_key->ipv4_dst,
			     tun_key->ipv4_tos,
			     tun_key->ipv4_ttl, df,
			     src_port, dst_port,
			     htonl(be64_to_cpu(tun_key->tun_id) << 8));
	if (err < 0)
		ip_rt_put(rt);
error:
	return err;
}
Ejemplo n.º 11
0
static int bpf_dp_ctx_init(struct bpf_dp_context *ctx)
{
	struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(ctx->skb)->tun_key;

	if (skb_headroom(ctx->skb) < 64) {
		if (pskb_expand_head(ctx->skb, 64, 0, GFP_ATOMIC))
			return -ENOMEM;
	}
	ctx->context.length = ctx->skb->len;
	ctx->context.vlan_tag = vlan_tx_tag_present(ctx->skb) ?
			vlan_tx_tag_get(ctx->skb) : 0;
	ctx->context.hw_csum = (ctx->skb->ip_summed == CHECKSUM_PARTIAL);
	if (tun_key) {
		ctx->context.tun_key.tun_id =
				be32_to_cpu(be64_get_low32(tun_key->tun_id));
		ctx->context.tun_key.src_ip = be32_to_cpu(tun_key->ipv4_src);
		ctx->context.tun_key.dst_ip = be32_to_cpu(tun_key->ipv4_dst);
		ctx->context.tun_key.tos = tun_key->ipv4_tos;
		ctx->context.tun_key.ttl = tun_key->ipv4_ttl;
	} else {
		memset(&ctx->context.tun_key, 0,
		       sizeof(struct bpf_ipv4_tun_key));
	}

	return 0;
}
Ejemplo n.º 12
0
int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,
			 struct sk_buff *skb, struct sw_flow_key *key)
{
	/* Extract metadata from packet. */
	if (tun_info) {
		memcpy(&key->tun_key, &tun_info->tunnel, sizeof(key->tun_key));

		BUILD_BUG_ON(((1 << (sizeof(tun_info->options_len) * 8)) - 1) >
			     sizeof(key->tun_opts));

		if (tun_info->options) {
			memcpy(GENEVE_OPTS(key, tun_info->options_len),
			       tun_info->options, tun_info->options_len);
			key->tun_opts_len = tun_info->options_len;
		} else {
			key->tun_opts_len = 0;
		}
	} else {
		key->tun_opts_len = 0;
		memset(&key->tun_key, 0, sizeof(key->tun_key));
	}

	key->phy.priority = skb->priority;
	key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
	key->phy.skb_mark = skb->mark;
	key->ovs_flow_hash = 0;
	key->recirc_id = 0;

	return key_extract(skb, key);
}
Ejemplo n.º 13
0
static int output_userspace(struct datapath *dp, struct sk_buff *skb,
			    const struct nlattr *attr)
{
	struct dp_upcall_info upcall;
	const struct nlattr *a;
	int rem;

	upcall.cmd = OVS_PACKET_CMD_ACTION;
	upcall.key = &OVS_CB(skb)->flow->key;
	upcall.userdata = NULL;
	upcall.pid = 0;

	for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
		 a = nla_next(a, &rem)) {
		switch (nla_type(a)) {
		case OVS_USERSPACE_ATTR_USERDATA:
			upcall.userdata = a;
			break;

		case OVS_USERSPACE_ATTR_PID:
			upcall.pid = nla_get_u32(a);
			break;
		}
	}

	return ovs_dp_upcall(dp, skb, &upcall);
}
Ejemplo n.º 14
0
static void __gre_build_header(struct sk_buff *skb,
			       int tunnel_hlen,
			       bool is_gre64)
{
	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
	__be32 *options = (__be32 *)(skb_network_header(skb) + tunnel_hlen
			- GRE_HEADER_SECTION);
	struct gre_base_hdr *greh = (struct gre_base_hdr *) skb_transport_header(skb);
	greh->protocol = htons(ETH_P_TEB);
	greh->flags = 0;

	/* Work backwards over the options so the checksum is last. */
	if (tun_key->tun_flags & OVS_TNL_F_KEY || is_gre64) {
		greh->flags |= GRE_KEY;
		if (is_gre64) {
			/* Set higher 32 bits to seq. */
			*options = be64_get_high32(tun_key->tun_id);
			options--;
			greh->flags |= GRE_SEQ;
		}
		*options = be64_get_low32(tun_key->tun_id);
		options--;
	}

	if (tun_key->tun_flags & OVS_TNL_F_CSUM) {
		greh->flags |= GRE_CSUM;
		*options = 0;
		*(__sum16 *)options = csum_fold(skb_checksum(skb,
						skb_transport_offset(skb),
						skb->len - skb_transport_offset(skb),
						0));
	}
}
Ejemplo n.º 15
0
/* Execute a list of actions against 'skb'. */
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
{
	struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);

	return do_execute_actions(dp, skb, acts->actions,
					 acts->actions_len, false);
}
Ejemplo n.º 16
0
static int __send(struct vport *vport, struct sk_buff *skb,
		  int tunnel_hlen,
		  __be32 seq, __be16 gre64_flag)
{
	struct ovs_key_ipv4_tunnel *tun_key = &OVS_CB(skb)->tun_info->tunnel;
	struct rtable *rt;
	int min_headroom;
	__be16 df;
	__be32 saddr;
	int err;

	/* Route lookup */
	saddr = tun_key->ipv4_src;
	rt = find_route(ovs_dp_get_net(vport->dp),
			&saddr, tun_key->ipv4_dst,
			IPPROTO_GRE, tun_key->ipv4_tos,
			skb->mark);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		goto error;
	}

	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
			+ tunnel_hlen + sizeof(struct iphdr)
			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);

	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
		int head_delta = SKB_DATA_ALIGN(min_headroom -
						skb_headroom(skb) +
						16);
		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
					0, GFP_ATOMIC);
		if (unlikely(err))
			goto err_free_rt;
	}
Ejemplo n.º 17
0
static int handle_fragments(struct net *net, struct sw_flow_key *key,
			    u16 zone, struct sk_buff *skb)
{
	struct ovs_skb_cb ovs_cb = *OVS_CB(skb);

	if (key->eth.type == htons(ETH_P_IP)) {
		enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
		int err;

		memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
		err = ip_defrag(net, skb, user);
		if (err)
			return err;

		ovs_cb.mru = IPCB(skb)->frag_max_size;
	} else if (key->eth.type == htons(ETH_P_IPV6)) {
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
		enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
		struct sk_buff *reasm;

		memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
		reasm = nf_ct_frag6_gather(net, skb, user);
		if (!reasm)
			return -EINPROGRESS;

		if (skb == reasm)
			return -EINVAL;

		key->ip.proto = ipv6_hdr(reasm)->nexthdr;
		skb_morph(skb, reasm);
		consume_skb(reasm);
		ovs_cb.mru = IP6CB(skb)->frag_max_size;
#else
		return -EPFNOSUPPORT;
#endif
	} else {
		return -EPFNOSUPPORT;
	}

	key->ip.frag = OVS_FRAG_TYPE_NONE;
	skb_clear_hash(skb);
	skb->ignore_df = 1;
	*OVS_CB(skb) = ovs_cb;

	return 0;
}
Ejemplo n.º 18
0
static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
				   struct ip_tunnel_info *egress_tun_info)
{
	return ovs_tunnel_get_egress_info(egress_tun_info,
					  ovs_dp_get_net(vport->dp),
					  OVS_CB(skb)->egress_tun_info,
					  IPPROTO_GRE, skb->mark, 0, 0);
}
Ejemplo n.º 19
0
/**
 *	ovs_vport_receive - pass up received packet to the datapath for processing
 *
 * @vport: vport that received the packet
 * @skb: skb that was received
 *
 * Must be called with rcu_read_lock.  The packet cannot be shared and
 * skb->data should point to the Ethernet header.  The caller must have already
 * called compute_ip_summed() to initialize the checksumming fields.
 */
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
{
	struct vport_percpu_stats *stats;

	stats = this_cpu_ptr(vport->percpu_stats);
	u64_stats_update_begin(&stats->sync);
	stats->rx_packets++;
	stats->rx_bytes += skb->len;
	u64_stats_update_end(&stats->sync);

	if (!(vport->ops->flags & VPORT_F_FLOW))
		OVS_CB(skb)->flow = NULL;

	if (!(vport->ops->flags & VPORT_F_TUN_ID))
		OVS_CB(skb)->tun_key = NULL;

	ovs_dp_process_received_packet(vport, skb);
}
Ejemplo n.º 20
0
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->sport;
	struct rtable *rt;
	struct flowi fl;
	__be16 src_port;
	int port_min;
	int port_max;
	__be16 df;
	int err;

	if (unlikely(!OVS_CB(skb)->tun_key)) {
		err = -EINVAL;
		goto error;
	}

	/* Route lookup */
	memset(&fl, 0, sizeof(fl));
	fl.fl4_dst = OVS_CB(skb)->tun_key->ipv4_dst;
	fl.fl4_src = OVS_CB(skb)->tun_key->ipv4_src;
	fl.fl4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos);
	fl.mark = skb->mark;
	fl.proto = IPPROTO_UDP;

	err = ip_route_output_key(net, &rt, &fl);
	if (err)
		goto error;

	df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
		htons(IP_DF) : 0;

	skb->local_df = 1;

	inet_get_local_port_range(&port_min, &port_max);
	src_port = vxlan_src_port(port_min, port_max, skb);

	err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb,
			     fl.fl4_src, OVS_CB(skb)->tun_key->ipv4_dst,
			     OVS_CB(skb)->tun_key->ipv4_tos,
			     OVS_CB(skb)->tun_key->ipv4_ttl, df,
			     src_port, dst_port,
			     htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8));
	if (err < 0)
		ip_rt_put(rt);
error:
	return err;
}
Ejemplo n.º 21
0
static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct ovs_key_ipv4_tunnel *tun_key;
	struct flowi4 fl;
	struct rtable *rt;
	int min_headroom;
	int tunnel_hlen;
	__be16 df;
	int err;

	if (unlikely(!OVS_CB(skb)->egress_tun_key)) {
		err = -EINVAL;
		goto error;
	}

	tun_key = OVS_CB(skb)->egress_tun_key;
	/* Route lookup */
	memset(&fl, 0, sizeof(fl));
	fl.daddr = tun_key->ipv4_dst;
	fl.saddr = tun_key->ipv4_src;
	fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos);
	fl.flowi4_mark = skb->mark;
	fl.flowi4_proto = IPPROTO_GRE;

	rt = ip_route_output_key(net, &fl);
	if (IS_ERR(rt))
		return PTR_ERR(rt);

	tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags);

	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
			+ tunnel_hlen + sizeof(struct iphdr)
			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
		int head_delta = SKB_DATA_ALIGN(min_headroom -
						skb_headroom(skb) +
						16);
		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
					0, GFP_ATOMIC);
		if (unlikely(err))
			goto err_free_rt;
	}
Ejemplo n.º 22
0
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
	struct rtable *rt;
	__be16 src_port;
	__be32 saddr;
	__be16 df;
	int err;

	if (unlikely(!OVS_CB(skb)->tun_key)) {
		err = -EINVAL;
		goto error;
	}

	/* Route lookup */
	saddr = OVS_CB(skb)->tun_key->ipv4_src;
	rt = find_route(ovs_dp_get_net(vport->dp),
			&saddr,
			OVS_CB(skb)->tun_key->ipv4_dst,
			IPPROTO_UDP,
			OVS_CB(skb)->tun_key->ipv4_tos,
			skb->mark);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		goto error;
	}

	df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
		htons(IP_DF) : 0;

	skb->local_df = 1;

	src_port = udp_flow_src_port(net, skb, 0, 0, true);

	err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
			     saddr, OVS_CB(skb)->tun_key->ipv4_dst,
			     OVS_CB(skb)->tun_key->ipv4_tos,
			     OVS_CB(skb)->tun_key->ipv4_ttl, df,
			     src_port, dst_port,
			     htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8));
	if (err < 0)
		ip_rt_put(rt);
error:
	return err;
}
Ejemplo n.º 23
0
Archivo: vport.c Proyecto: 7799/linux
/**
 *	ovs_vport_receive - pass up received packet to the datapath for processing
 *
 * @vport: vport that received the packet
 * @skb: skb that was received
 * @tun_key: tunnel (if any) that carried packet
 *
 * Must be called with rcu_read_lock.  The packet cannot be shared and
 * skb->data should point to the Ethernet header.
 */
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
		       struct ovs_key_ipv4_tunnel *tun_key)
{
	struct pcpu_sw_netstats *stats;

	stats = this_cpu_ptr(vport->percpu_stats);
	u64_stats_update_begin(&stats->syncp);
	stats->rx_packets++;
	stats->rx_bytes += skb->len;
	u64_stats_update_end(&stats->syncp);

	OVS_CB(skb)->tun_key = tun_key;
	ovs_dp_process_received_packet(vport, skb);
}
Ejemplo n.º 24
0
/**
 *	ovs_vport_receive - pass up received packet to the datapath for processing
 *
 * @vport: vport that received the packet
 * @skb: skb that was received
 * @tun_key: tunnel (if any) that carried packet
 *
 * Must be called with rcu_read_lock.  The packet cannot be shared and
 * skb->data should point to the Ethernet header.
 */
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
		       const struct ovs_tunnel_info *tun_info)
{
	struct pcpu_sw_netstats *stats;
	struct sw_flow_key key;
	int error;

	stats = this_cpu_ptr(vport->percpu_stats);
	u64_stats_update_begin(&stats->syncp);
	stats->rx_packets++;
	stats->rx_bytes += skb->len + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
	u64_stats_update_end(&stats->syncp);

	OVS_CB(skb)->input_vport = vport;
	OVS_CB(skb)->egress_tun_info = NULL;
	/* Extract flow from 'skb' into 'key'. */
	error = ovs_flow_key_extract(tun_info, skb, &key);
	if (unlikely(error)) {
		kfree_skb(skb);
		return;
	}
	ovs_dp_process_packet(skb, &key);
}
Ejemplo n.º 25
0
static int vxlan_ext_gbp(struct sk_buff *skb)
{
	const struct ovs_tunnel_info *tun_info;
	const struct ovs_vxlan_opts *opts;

	tun_info = OVS_CB(skb)->egress_tun_info;
	opts = tun_info->options;

	if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT &&
	    tun_info->options_len >= sizeof(*opts))
		return opts->gbp;
	else
		return 0;
}
Ejemplo n.º 26
0
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
				     struct ovs_tunnel_info *egress_tun_info)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
	__be16 src_port;

	src_port = udp_flow_src_port(net, skb, 0, 0, true);

	return ovs_tunnel_get_egress_info(egress_tun_info, net,
					  OVS_CB(skb)->egress_tun_info,
					  IPPROTO_UDP, skb->mark,
					  src_port, dst_port);
}
Ejemplo n.º 27
0
static int stt_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
				   struct ovs_tunnel_info *egress_tun_info)
{
	struct stt_port *stt_port = stt_vport(vport);
	struct net *net = ovs_dp_get_net(vport->dp);
	__be16 dport = inet_sk(stt_port->stt_sock->sock->sk)->inet_sport;
	__be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);

	/* Get tp_src and tp_dst, refert to stt_build_header().
	 */
	return ovs_tunnel_get_egress_info(egress_tun_info,
					  ovs_dp_get_net(vport->dp),
					  OVS_CB(skb)->egress_tun_info,
					  IPPROTO_TCP, skb->mark, sport, dport);
}
Ejemplo n.º 28
0
/* Called with rcu_read_lock and BH disabled. */
static int gre_rcv(struct sk_buff *skb)
{
	struct ovs_net *ovs_net;
	struct vport *vport;
	int hdr_len;
	struct iphdr *iph;
	struct ovs_key_ipv4_tunnel tun_key;
	__be16 gre_flags;
	u32 tnl_flags;
	__be64 key;
	bool is_gre64;

	if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
		goto error;
	if (unlikely(!check_checksum(skb)))
		goto error;

	hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &is_gre64);
	if (unlikely(hdr_len < 0))
		goto error;

	ovs_net = net_generic(dev_net(skb->dev), ovs_net_id);
	if (is_gre64)
		vport = rcu_dereference(ovs_net->vport_net.gre64_vport);
	else
		vport = rcu_dereference(ovs_net->vport_net.gre_vport);
	if (unlikely(!vport))
		goto error;

	if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN)))
		goto error;

	iph = ip_hdr(skb);
	tnl_flags = gre_flags_to_tunnel_flags(gre_flags, is_gre64);
	tnl_tun_key_init(&tun_key, iph, key, tnl_flags);
	OVS_CB(skb)->tun_key = &tun_key;

	__skb_pull(skb, hdr_len);
	skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);

	ovs_tnl_rcv(vport, skb);
	return 0;

error:
	kfree_skb(skb);
	return 0;
}
Ejemplo n.º 29
0
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
				     struct ovs_tunnel_info *egress_tun_info)
{
	struct net *net = ovs_dp_get_net(vport->dp);
	struct vxlan_port *vxlan_port = vxlan_vport(vport);
	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
	__be16 src_port;
	int port_min;
	int port_max;

	inet_get_local_port_range(net, &port_min, &port_max);
	src_port = vxlan_src_port(port_min, port_max, skb);

	return ovs_tunnel_get_egress_info(egress_tun_info, net,
					  OVS_CB(skb)->egress_tun_info,
					  IPPROTO_UDP, skb->mark,
					  src_port, dst_port);
}
Ejemplo n.º 30
0
static struct sk_buff *__build_header(struct sk_buff *skb,
				      int tunnel_hlen)
{
	const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->egress_tun_key;
	struct tnl_ptk_info tpi;

	skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM));
	if (IS_ERR(skb))
		return NULL;

	tpi.flags = filter_tnl_flags(tun_key->tun_flags);
	tpi.proto = htons(ETH_P_TEB);
	tpi.key = be64_get_low32(tun_key->tun_id);
	tpi.seq = 0;
	gre_build_header(skb, &tpi, tunnel_hlen);

	return skb;
}