Esempio n. 1
0
File: vport.c Progetto: JunoZhu/ovs
int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall,
			       struct net *net,
			       struct sk_buff *skb,
			       u8 ipproto,
			       __be16 tp_src,
			       __be16 tp_dst)
{
	struct ip_tunnel_info *egress_tun_info = upcall->egress_tun_info;
	struct ip_tunnel_info *tun_info = skb_tunnel_info(skb);
	const struct ip_tunnel_key *tun_key;
	u32 skb_mark = skb->mark;
	struct rtable *rt;
	struct flowi4 fl;

	if (unlikely(!tun_info))
		return -EINVAL;
	if (ip_tunnel_info_af(tun_info) != AF_INET)
		return -EINVAL;

	tun_key = &tun_info->key;

	/* Route lookup to get srouce IP address.
	 * The process may need to be changed if the corresponding process
	 * in vports ops changed.
	 */
	rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, ipproto);
	if (IS_ERR(rt))
		return PTR_ERR(rt);

	ip_rt_put(rt);

	/* Generate egress_tun_info based on tun_info,
	 * saddr, tp_src and tp_dst
	 */
	ip_tunnel_key_init(&egress_tun_info->key,
			   fl.saddr, tun_key->u.ipv4.dst,
			   tun_key->tos,
			   tun_key->ttl,
			   tp_src, tp_dst,
			   tun_key->tun_id,
			   tun_key->tun_flags);
	egress_tun_info->options_len = tun_info->options_len;
	egress_tun_info->mode = tun_info->mode;
	upcall->egress_tun_opts = ip_tunnel_info_opts(tun_info);
	return 0;
}
Esempio n. 2
0
static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
			       int opts_len, struct netlink_ext_ack *extack)
{
	info->options_len = opts_len;
	switch (nla_type(nla_data(nla))) {
	case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
#if IS_ENABLED(CONFIG_INET)
		info->key.tun_flags |= TUNNEL_GENEVE_OPT;
		return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
					    opts_len, extack);
#else
		return -EAFNOSUPPORT;
#endif
	default:
		NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type");
		return -EINVAL;
	}
}
Esempio n. 3
0
static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
		      int gre_hdr_len)
{
	struct net *net = dev_net(skb->dev);
	struct metadata_dst *tun_dst = NULL;
	struct erspan_base_hdr *ershdr;
	struct erspan_metadata *pkt_md;
	struct ip_tunnel_net *itn;
	struct ip_tunnel *tunnel;
	const struct iphdr *iph;
	struct erspan_md2 *md2;
	int ver;
	int len;

	itn = net_generic(net, erspan_net_id);
	len = gre_hdr_len + sizeof(*ershdr);

	/* Check based hdr len */
	if (unlikely(!pskb_may_pull(skb, len)))
		return PACKET_REJECT;

	iph = ip_hdr(skb);
	ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
	ver = ershdr->ver;

	/* The original GRE header does not have key field,
	 * Use ERSPAN 10-bit session ID as key.
	 */
	tpi->key = cpu_to_be32(get_session_id(ershdr));
	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
				  tpi->flags,
				  iph->saddr, iph->daddr, tpi->key);

	if (tunnel) {
		len = gre_hdr_len + erspan_hdr_len(ver);
		if (unlikely(!pskb_may_pull(skb, len)))
			return PACKET_REJECT;

		ershdr = (struct erspan_base_hdr *)skb->data;
		pkt_md = (struct erspan_metadata *)(ershdr + 1);

		if (__iptunnel_pull_header(skb,
					   len,
					   htons(ETH_P_TEB),
					   false, false) < 0)
			goto drop;

		if (tunnel->collect_md) {
			struct ip_tunnel_info *info;
			struct erspan_metadata *md;
			__be64 tun_id;
			__be16 flags;

			tpi->flags |= TUNNEL_KEY;
			flags = tpi->flags;
			tun_id = key32_to_tunnel_id(tpi->key);

			tun_dst = rpl_ip_tun_rx_dst(skb, flags, tun_id, sizeof(*md));
			if (!tun_dst)
				return PACKET_REJECT;

			md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
			md->version = ver;
			md2 = &md->u.md2;
			memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
						       ERSPAN_V2_MDSIZE);

			info = &tun_dst->u.tun_info;
			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
			info->options_len = sizeof(*md);
		}

		skb_reset_mac_header(skb);
		ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst);
		kfree(tun_dst);
		return PACKET_RCVD;
	}
drop:
	kfree_skb(skb);
	return PACKET_RCVD;
}