Skip to content

Commit

Permalink
flow_dissector: extract more ICMP information
Browse files Browse the repository at this point in the history
The ICMP flow dissector currently parses only the Type and Code fields.
Some ICMP packets (echo, timestamp) have a 16 bit Identifier field which
is used to correlate packets.
Add such field in flow_dissector_key_icmp and replace skb_flow_get_be16()
with a more complex function which populate this field.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Matteo Croce authored and David S. Miller committed Oct 31, 2019
1 parent 3b336d6 commit 5dec597
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 32 deletions.
19 changes: 11 additions & 8 deletions include/net/flow_dissector.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <linux/in6.h>
#include <uapi/linux/if_ether.h>

struct sk_buff;

/**
* struct flow_dissector_key_control:
* @thoff: Transport header offset
Expand Down Expand Up @@ -156,19 +158,16 @@ struct flow_dissector_key_ports {

/**
* flow_dissector_key_icmp:
* @ports: type and code of ICMP header
* icmp: ICMP type (high) and code (low)
* type: ICMP type
* code: ICMP code
* id: session identifier
*/
struct flow_dissector_key_icmp {
union {
__be16 icmp;
struct {
u8 type;
u8 code;
};
struct {
u8 type;
u8 code;
};
u16 id;
};

/**
Expand Down Expand Up @@ -282,6 +281,7 @@ struct flow_keys {
struct flow_dissector_key_vlan cvlan;
struct flow_dissector_key_keyid keyid;
struct flow_dissector_key_ports ports;
struct flow_dissector_key_icmp icmp;
/* 'addrs' must be the last member */
struct flow_dissector_key_addrs addrs;
};
Expand Down Expand Up @@ -316,6 +316,9 @@ static inline bool flow_keys_have_l4(const struct flow_keys *keys)
}

u32 flow_hash_from_keys(struct flow_keys *keys);
void skb_flow_get_icmp_tci(const struct sk_buff *skb,
struct flow_dissector_key_icmp *key_icmp,
void *data, int thoff, int hlen);

static inline bool dissector_uses_key(const struct flow_dissector *flow_dissector,
enum flow_dissector_key_id key_id)
Expand Down
74 changes: 50 additions & 24 deletions net/core/flow_dissector.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,6 @@ int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr)
mutex_unlock(&flow_dissector_mutex);
return 0;
}
/**
* skb_flow_get_be16 - extract be16 entity
* @skb: sk_buff to extract from
* @poff: offset to extract at
* @data: raw buffer pointer to the packet
* @hlen: packet header length
*
* The function will try to retrieve a be32 entity at
* offset poff
*/
static __be16 skb_flow_get_be16(const struct sk_buff *skb, int poff,
void *data, int hlen)
{
__be16 *u, _u;

u = __skb_header_pointer(skb, poff, sizeof(_u), data, hlen, &_u);
if (u)
return *u;

return 0;
}

/**
* __skb_flow_get_ports - extract the upper layer ports and return them
Expand Down Expand Up @@ -234,8 +213,54 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
}
EXPORT_SYMBOL(__skb_flow_get_ports);

/* If FLOW_DISSECTOR_KEY_ICMP is set, get the Type and Code from an ICMP packet
* using skb_flow_get_be16().
static bool icmp_has_id(u8 type)
{
switch (type) {
case ICMP_ECHO:
case ICMP_ECHOREPLY:
case ICMP_TIMESTAMP:
case ICMP_TIMESTAMPREPLY:
case ICMPV6_ECHO_REQUEST:
case ICMPV6_ECHO_REPLY:
return true;
}

return false;
}

/**
* skb_flow_get_icmp_tci - extract ICMP(6) Type, Code and Identifier fields
* @skb: sk_buff to extract from
* @key_icmp: struct flow_dissector_key_icmp to fill
* @data: raw buffer pointer to the packet
* @toff: offset to extract at
* @hlen: packet header length
*/
void skb_flow_get_icmp_tci(const struct sk_buff *skb,
struct flow_dissector_key_icmp *key_icmp,
void *data, int thoff, int hlen)
{
struct icmphdr *ih, _ih;

ih = __skb_header_pointer(skb, thoff, sizeof(_ih), data, hlen, &_ih);
if (!ih)
return;

key_icmp->type = ih->type;
key_icmp->code = ih->code;

/* As we use 0 to signal that the Id field is not present,
* avoid confusion with packets without such field
*/
if (icmp_has_id(ih->type))
key_icmp->id = ih->un.echo.id ? : 1;
else
key_icmp->id = 0;
}
EXPORT_SYMBOL(skb_flow_get_icmp_tci);

/* If FLOW_DISSECTOR_KEY_ICMP is set, dissect an ICMP packet
* using skb_flow_get_icmp_tci().
*/
static void __skb_flow_dissect_icmp(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
Expand All @@ -250,7 +275,8 @@ static void __skb_flow_dissect_icmp(const struct sk_buff *skb,
key_icmp = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_ICMP,
target_container);
key_icmp->icmp = skb_flow_get_be16(skb, thoff, data, hlen);

skb_flow_get_icmp_tci(skb, key_icmp, data, thoff, hlen);
}

void skb_flow_dissect_meta(const struct sk_buff *skb,
Expand Down

0 comments on commit 5dec597

Please sign in to comment.