Subject: Re: [RFC] [PATCH] [XFRM]: Restrict upper layer information by bundle.

From: Masahide NAKAMURA <[email-masked]>
Date: Thu, 12 Apr 2007 14:42:00 +0900

Hello,

I sent the patch, which is required for IPsec usage by Mobile IPv6.
I have not obtained any comments yet. Does anybody have it?

I hope it to be applied.

Thanks,

Masahide NAKAMURA wrote:
> On MIPv6 usage, XFRM sub policy is enabled.
> When main (IPsec) and sub (MIPv6) policy selectors have the same
> address set but different upper layer information (i.e. protocol
> number and its ports or type/code), multiple bundle should be created.
> However, currently we have issue to use the same bundle created for
> the first time with all flows covered by the case.
> 
> It is useful for the bundle to have the upper layer information
> to be restructured correctly if it does not match with the flow.
> 
> 1. Bundle was created by two policies
> Selector from another policy is added to xfrm_dst.
> If the flow does not match the selector, it goes to slow path to
> restructure new bundle by single policy.
> 
> 2. Bundle was created by one policy
> Flow cache is added to xfrm_dst as originated one. If the flow does
> not match the cache, it goes to slow path to try searching another
> policy.
> 
> Signed-off-by: Masahide NAKAMURA <[email-masked]>
> ---
>  include/net/flow.h     |    6 +++++
>  include/net/xfrm.h     |   10 ++++++++
>  net/xfrm/xfrm_policy.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 71 insertions(+), 0 deletions(-)
> 
> diff --git a/include/net/flow.h b/include/net/flow.h
> index ce4b10d..f3cc1f8 100644
> --- a/include/net/flow.h
> +++ b/include/net/flow.h
> @@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
>  extern void flow_cache_flush(void);
>  extern atomic_t flow_cache_genid;
>  
> +static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2)
> +{
> +	return (fl1->proto == fl2->proto &&
> +		!memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u)));
> +}
> +
>  #endif
> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index 5a00aa8..c216c5e 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -584,6 +584,10 @@ struct xfrm_dst
>  		struct rt6_info		rt6;
>  	} u;
>  	struct dst_entry *route;
> +#ifdef CONFIG_XFRM_SUB_POLICY
> +	struct flowi *origin;
> +	struct xfrm_selector *partner;
> +#endif
>  	u32 genid;
>  	u32 route_mtu_cached;
>  	u32 child_mtu_cached;
> @@ -596,6 +600,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
>  	dst_release(xdst->route);
>  	if (likely(xdst->u.dst.xfrm))
>  		xfrm_state_put(xdst->u.dst.xfrm);
> +#ifdef CONFIG_XFRM_SUB_POLICY
> +	kfree(xdst->origin);
> +	xdst->origin = NULL;
> +	kfree(xdst->partner);
> +	xdst->partner = NULL;
> +#endif
>  }
>  
>  extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 1942575..4a2f68f 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -1330,6 +1330,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
>  	return err;
>  }
>  
> +static int inline
> +xfrm_dst_alloc_copy(void **target, void *src, int size)
> +{
> +	if (!*target) {
> +		*target = kmalloc(size, GFP_ATOMIC);
> +		if (!*target)
> +			return -ENOMEM;
> +	}
> +	memcpy(*target, src, size);
> +	return 0;
> +}
> +
> +static int inline
> +xfrm_dst_update_parent(struct dst_entry *dst, struct xfrm_selector *sel)
> +{
> +#ifdef CONFIG_XFRM_SUB_POLICY
> +	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
> +	return xfrm_dst_alloc_copy((void **)&(xdst->partner),
> +				   sel, sizeof(*sel));
> +#else
> +	return 0;
> +#endif
> +}
> +
> +static int inline
> +xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
> +{
> +#ifdef CONFIG_XFRM_SUB_POLICY
> +	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
> +	return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
> +#else
> +	return 0;
> +#endif
> +}
>  
>  static int stale_bundle(struct dst_entry *dst);
>  
> @@ -1518,6 +1552,18 @@ restart:
>  			err = -EHOSTUNREACH;
>  			goto error;
>  		}
> +
> +		if (npols > 1)
> +			err = xfrm_dst_update_parent(dst, &pols[1]->selector);
> +		else
> +			err = xfrm_dst_update_origin(dst, fl);
> +		if (unlikely(err)) {
> +			write_unlock_bh(&policy->lock);
> +			if (dst)
> +				dst_free(dst);
> +			goto error;
> +		}
> +
>  		dst->next = policy->bundles;
>  		policy->bundles = dst;
>  		dst_hold(dst);
> @@ -1933,6 +1979,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
>  	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
>  	    (dst->dev && !netif_running(dst->dev)))
>  		return 0;
> +#ifdef CONFIG_XFRM_SUB_POLICY
> +	if (fl) {
> +		if (first->origin && !flow_cache_uli_match(first->origin, fl))
> +			return 0;
> +		if (first->partner &&
> +		    !xfrm_selector_match(first->partner, fl, family))
> +			return 0;
> +	}
> +#endif
>  
>  	last = NULL;
>  

-- 
Masahide NAKAMURA