Config.in:
CONFIG_RT6_POLICY
	net/ipv6/Config.in ǥȥȤƤ롣ƤΤ net/ipv6/route.c Τߤ #undef Ƥ롣
	CONFIG_RT6_POLICY αƶϰ
		int	ip6_rt_policy = 0;
		struct pol_chain *rt6_pol_list = NULL;

		static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);
		static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);
		static struct rt6_info	*rt6_flow_lookup(struct rt6_info *rt, struct in6_addr *daddr,
							struct in6_addr *saddr, struct fl_acc_args *args);
	-> ip6_rt_policy οѹؿ̵

CONFIG_IPV6_FIREWALL
	net/ipv6/Config.in ǥȥȤƤ롣Ƥս̵(Ȥ ip6_fwnetfilter ء)
	include/linux/netlink.h ˤ NETLINK_IP6_FW 롣
	include/net/ip6_fw.h, net/ipv6/ip6_fw.c ¸ߤ뤬ѤƤʤ

ȹߴؿ

ipv6_rcv:
- NF_HOOK(pf, hook, skb, indev, outdev, okfn)	: hooks[pf][hook]  nf_hook_slow() ˰ܤꡢʤ okfn( = ip6_rcv_finish) ˰ܤ롣
  - nf_hook_slow(pf, hook, skb, indev, outdev, okfn)
    - nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, outdev, &elem, okfn) : elem->hook(hook, skb, indev, outdev, okfn) ֤ͤ
						: NF_REPEAT ʤ鼡 nf_hook_ops  hooks[pf][hook] ޤǷ֤
						: ҤäΤ̵ NF_ACCEPT ֤롣
      - elem->hook()
+++	typedef unsigned int nf_hookfn(unsigned int hooknum, sk_buff **skb, net_device *in, net_device *out, int (*okfn)(sk_buff *))

    - nf_queue(skb, elem, pf, hook, indev, outdev, okfn) : queue_handler[pf].outfn  NULL ʤ kfree(skb)
						: info = kmalloc(sizeof(*info), GFP_ATOMIC)  NULL ʤ kfree(skb)
						: info = (struct nf_info){(struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn}
						: queue_handler[pf].outfn(skb, info, queue_handler[pf].data)  < 0  kfree({info,skb})
      - queue_handler[pf].outfn()
+++	typedef int (*nf_queue_outfn_t)(sk_buff *skb, nf_info *info, void *data)

ip6_rcv_finish:
- ip6_route_input(skb)				: skb->dst == NULL ΤȤƤӽФ롣
  - rt6_flow_lookup_in(rt, skb)			: rt  skb Ф rt6_info 뤫򸡺̵֤ ip6_null_entry ֤
    - arg.type = FL_ARG_FORWARD; arg.fl_u.skb = skb;: struct fl_acc_args 
    - rt6_flow_lookup(rt, daddr, saddr, args)	: frule->ops->accept ƤӽФơ˹礨 rt6_info ̵֤ ip6_null_entry
      - for (pol = rt6_pol_list; .. )		: struct pol_chain ˹礦ݥꥷ򸡺
        - fib6_lookup(pol->rules, daddr, saddr)	: pol->rules ʲǾ˹礦 fib6_node ֤
        - for (sprt = fn->leaf; .. )
          - frule = sprt->rt6i_flowr		: struct flow_rule 
          - res = frule->ops->accept(rt, sprt, args, &nrt): FLOWR_SELECT, _CLEAR, _NODECISION ֤
***	struct flow_rule {
		struct flow_rule_ops {
+++			int (*accept)(rt6_info *rt, rt6_info *rule, fl_acc_args *args, rt6_info **nrt);
		} *ops;
		unsigned char private[0];
	};

- skb->dst->input(skb)
*** struct sk_buff {
	/* These two members must be first. */
	struct sk_buff	* next;			/* Next buffer in list 				*/
	struct sk_buff	* prev;			/* Previous buffer in list 			*/

	struct sk_buff_head * list;		/* List we are on				*/
	struct sock	*sk;			/* Socket we are owned by 			*/
	struct timeval	stamp;			/* Time we arrived				*/
	struct net_device	*dev;		/* Device we arrived on/are leaving by		*/

	/* Transport layer header */
	union
	{
		struct tcphdr	*th;
		struct udphdr	*uh;
		struct icmphdr	*icmph;
		struct icmp6hdr	*icmp6h;
		struct igmphdr	*igmph;
		struct iphdr	*ipiph;
		struct spxhdr	*spxh;
		unsigned char	*raw;
	} h;

	/* Network layer header */
	union
	{
		struct iphdr	*iph;
		struct ipv6hdr	*ipv6h;
		struct arphdr	*arph;
		struct ipxhdr	*ipxh;
		unsigned char	*raw;
	} nh;
  
	/* Link layer header */
	union 
	{	
	  	struct ethhdr	*ethernet;
	  	unsigned char 	*raw;
	} mac;

+++	struct dst_entry
	{
		struct dst_entry        *next;
		atomic_t		__refcnt;	/* client references	*/
		int			__use;
		struct net_device       *dev;
		int			obsolete;
		int			flags;
	#define DST_HOST		1
		unsigned long		lastuse;
		unsigned long		expires;

		unsigned		mxlock;
		unsigned		pmtu;
		unsigned		window;
		unsigned		rtt;
		unsigned		rttvar;
		unsigned		ssthresh;
		unsigned		cwnd;
		unsigned		advmss;
		unsigned		reordering;

		unsigned long		rate_last;	/* rate limiting for ICMP */
		unsigned long		rate_tokens;

		int			error;

		struct neighbour	*neighbour;
		struct hh_cache		*hh;

+++		int			(*input)(struct sk_buff*);
		int			(*output)(struct sk_buff*);

	#ifdef CONFIG_NET_CLS_ROUTE
		__u32			tclassid;
	#endif

		struct  dst_ops	        *ops;
		
		char			info[0];
	} *dst;

	/* 
	 * This is the control buffer. It is free to use for every
	 * layer. Please put your private variables there. If you
	 * want to keep them across layers you have to do a skb_clone()
	 * first. This is owned by whoever has the skb queued ATM.
	 */ 
	char		cb[48];	 

	unsigned int 	len;			/* Length of actual data			*/
 	unsigned int 	data_len;
	unsigned int	csum;			/* Checksum 					*/
	unsigned char 	__unused,		/* Dead field, may be reused			*/
			cloned, 		/* head may be cloned (check refcnt to be sure). */
  			pkt_type,		/* Packet class					*/
  			ip_summed;		/* Driver fed us an IP checksum			*/
	__u32		priority;		/* Packet queueing priority			*/
	atomic_t	users;			/* User count - see datagram.c,tcp.c 		*/
	unsigned short	protocol;		/* Packet protocol from driver. 		*/
	unsigned short	security;		/* Security level of packet			*/
	unsigned int	truesize;		/* Buffer size 					*/

	unsigned char	*head;			/* Head of buffer 				*/
	unsigned char	*data;			/* Data head pointer				*/
	unsigned char	*tail;			/* Tail pointer					*/
	unsigned char 	*end;			/* End pointer					*/

	void 		(*destructor)(struct sk_buff *);	/* Destruct function		*/
    #ifdef CONFIG_NETFILTER
	/* Can be used for communication between hooks. */
        unsigned long	nfmark;
	/* Cache info */
	__u32		nfcache;
	/* Associated connection, if any */
	struct nf_ct_info *nfct;
    #ifdef CONFIG_NETFILTER_DEBUG
        unsigned int nf_debug;
    #endif
    #endif /*CONFIG_NETFILTER*/

    #if defined(CONFIG_HIPPI)
	union{
		__u32	ifield;
	} private;
    #endif

    #ifdef CONFIG_NET_SCHED
       __u32           tc_index;               /* traffic control index */
    #endif
    };

ݥꥷե륿

ip6_route_input:
- if (rt->rt6i_flags & RTF_CACHE)		: RTF_CACHE ˰äȤip6_rt_policy == 0  RTF_FLOW դƤȤȤʬ
  - rt6_device_match(rt, skb->dev->ifindex, strict) : rt->rt6i_dev  skb->dev õդʤä硢
						: IFF_LOOPBACK Фstrict ͤ ip6_null_entry 
  - dst_clone(rt->u.dst)			: rt->u.dst->__refcnt ͤ 1 ä
    - atomic_inc(atomic_t *)
  - if (rt->rt6i_flags & RTF_FLOW)		: rt6_flow_match_in  0 ֤Ƥ֡rt  u.next éäƤ
    - rt6_flow_match_in(sptr, skb)		: ե륿 FLR_INPUT ǤʤΡskb ȥե륿ͤפʤΤ 0 ֤
      - frule = rt->rt6i_filter			: struct flow_filter *frule  NULL ʤ 1 frule->type  FLR_INPUT Ǥʤ 0 ֤
      - filter = frule->u.filter		: struct pkt_filter *filter ˥롼ơ(__u32 *)((skb->h.raw) + filter->offset) 
						: filter->value Ȥ ^ Ȥä filter->mask Ȥ & äơ0 ʳʤ 0 ֤
*** ʬ
		word = (__u32 *) skb->h.raw;
		word += filter->offset;

		if ((*word ^ filter->value) & filter->mask) {
			res = 0;
			break;
		}

*** struct rt6_info {
	union {
		struct dst_entry	dst;
		struct rt6_info		*next;
	} u;

    #define rt6i_dev			u.dst.dev
    #define rt6i_nexthop			u.dst.neighbour
    #define rt6i_expires			u.dst.expires

	struct fib6_node		*rt6i_node;

	struct in6_addr			rt6i_gateway;
	
	u32				rt6i_flags;
	u32				rt6i_metric;
	u8				rt6i_hoplimit;
	atomic_t			rt6i_ref;

	union {
		struct flow_rule	*rt6iu_flowr;
		struct flow_filter {
			int				type;
			union {
+++				struct pkt_filter {
					atomic_t		refcnt;
					unsigned int		offset;
					__u32			value;
					__u32			mask;
					struct pkt_filter	*next;
				} *filter;
				struct sock		*sk;
			} u;
		} *rt6iu_filter;
	} flow_u;

    #define rt6i_flowr			flow_u.rt6iu_flowr
    #define rt6i_filter			flow_u.rt6iu_filter

	struct rt6key			rt6i_dst;
	struct rt6key			rt6i_src;
    };
