• P
    [SKFILTER]: Add SKF_ADF_NLATTR instruction · 4738c1db
    Patrick McHardy 提交于
    SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually
    parsing and walking attributes. It takes the offset at which to start
    searching in the 'A' register and the attribute type in the 'X' register
    and returns the offset in the 'A' register. When the attribute is not
    found it returns zero.
    
    A top-level attribute can be located using a filter like this
    (example for nfnetlink, using struct nfgenmsg):
    
    	...
    	{
    		/* A = offset of first attribute */
    		.code	= BPF_LD | BPF_IMM,
    		.k	= sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg)
    	},
    	{
    		/* X = CTA_PROTOINFO */
    		.code	= BPF_LDX | BPF_IMM,
    		.k	= CTA_PROTOINFO,
    	},
    	{
    		/* A = netlink attribute offset */
    		.code	= BPF_LD | BPF_B | BPF_ABS,
    		.k	= SKF_AD_OFF + SKF_AD_NLATTR
    	},
    	{
    		/* Exit if not found */
    		.code   = BPF_JMP | BPF_JEQ | BPF_K,
    		.k	= 0,
    		.jt	= <error>
    	},
    	...
    
    A nested attribute below the CTA_PROTOINFO attribute would then
    be parsed like this:
    
    	...
    	{
    		/* A += sizeof(struct nlattr) */
    		.code	= BPF_ALU | BPF_ADD | BPF_K,
    		.k	= sizeof(struct nlattr),
    	},
    	{
    		/* X = CTA_PROTOINFO_TCP */
    		.code	= BPF_LDX | BPF_IMM,
    		.k	= CTA_PROTOINFO_TCP,
    	},
    	{
    		/* A = netlink attribute offset */
    		.code	= BPF_LD | BPF_B | BPF_ABS,
    		.k	= SKF_AD_OFF + SKF_AD_NLATTR
    	},
    	...
    
    The data of an attribute can be loaded into 'A' like this:
    
    	...
    	{
    		/* X = A (attribute offset) */
    		.code	= BPF_MISC | BPF_TAX,
    	},
    	{
    		/* A = skb->data[X + k] */
    		.code 	= BPF_LD | BPF_B | BPF_IND,
    		.k	= sizeof(struct nlattr),
    	},
    	...
    Signed-off-by: NPatrick McHardy <kaber@trash.net>
    Signed-off-by: NDavid S. Miller <davem@davemloft.net>
    4738c1db
filter.h 4.0 KB