summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2019-01-09 16:26:19 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2019-01-09 16:26:19 +0100
commitbad27ca386276e64cd7a27abf3417b8a4be20fa4 (patch)
tree92ee68e602f3acaad34926aa80db2657bca4907d
parent70065ab63a90787c49f714c6e39fa1b112b5c8af (diff)
src: add igmp support
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--doc/payload-expression.txt28
-rw-r--r--include/datatype.h3
-rw-r--r--include/proto.h9
-rw-r--r--src/datatype.c1
-rw-r--r--src/parser_bison.y29
-rw-r--r--src/payload.c6
-rw-r--r--src/proto.c52
-rw-r--r--src/scanner.l3
-rw-r--r--tests/py/ip/igmp.t25
-rw-r--r--tests/py/ip/igmp.t.payload366
10 files changed, 517 insertions, 5 deletions
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index e1a10252..abaf52f0 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -151,6 +151,34 @@ MTU of path MTU discovery|
integer (16 bit)
|============================
+IGMP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*igmp* ['IGMP' 'header' 'field']
+
+This expression refers to IGMP header fields. When using it in *inet*,
+*bridge* or *netdev* families, it will cause an implicit dependency on IPv4 to
+be created. To match on unusual cases like IGMP over IPv6, one has to add an
+explicit *meta protocol ip6* match to the rule.
+
+.IGMP header expression
+[options="header"]
+|==================
+|Keyword|Description| Type
+|type|
+IGMP type field |
+igmp_type
+|mrt|
+IGMP maximum response time field |
+integer (8 bit)
+|checksum|
+ICMP checksum field |
+integer (16 bit)
+|group|
+Group address|
+integer (32 bit)
+|============================
+
IPV6 HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~
[verse]
diff --git a/include/datatype.h b/include/datatype.h
index f7092f06..14ece282 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -44,6 +44,7 @@
* @TYPE_DEVGROUP: devgroup code (integer subtype)
* @TYPE_DSCP: Differentiated Services Code Point (integer subtype)
* @TYPE_IFNAME: interface name (string subtype)
+ * @TYPE_IGMP: IGMP type (integer subtype)
*/
enum datatypes {
TYPE_INVALID,
@@ -88,6 +89,7 @@ enum datatypes {
TYPE_BOOLEAN,
TYPE_CT_EVENTBIT,
TYPE_IFNAME,
+ TYPE_IGMP_TYPE,
__TYPE_MAX
};
#define TYPE_MAX (__TYPE_MAX - 1)
@@ -248,6 +250,7 @@ extern const struct datatype icmp_type_type;
extern const struct datatype icmp_code_type;
extern const struct datatype icmpv6_code_type;
extern const struct datatype icmpx_code_type;
+extern const struct datatype igmp_type_type;
extern const struct datatype time_type;
extern const struct datatype boolean_type;
diff --git a/include/proto.h b/include/proto.h
index 9a9f9255..99c57a79 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -211,6 +211,14 @@ enum icmp_hdr_fields {
ICMPHDR_MTU,
};
+enum igmp_hdr_fields {
+ IGMPHDR_INVALID,
+ IGMPHDR_TYPE,
+ IGMPHDR_CHECKSUM,
+ IGMPHDR_MRT,
+ IGMPHDR_GROUP,
+};
+
enum icmp6_hdr_fields {
ICMP6HDR_INVALID,
ICMP6HDR_TYPE,
@@ -299,6 +307,7 @@ enum sctp_hdr_fields {
};
extern const struct proto_desc proto_icmp;
+extern const struct proto_desc proto_igmp;
extern const struct proto_desc proto_ah;
extern const struct proto_desc proto_esp;
extern const struct proto_desc proto_comp;
diff --git a/src/datatype.c b/src/datatype.c
index 6af1c843..0e745833 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -70,6 +70,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
[TYPE_FIB_ADDR] = &fib_addr_type,
[TYPE_BOOLEAN] = &boolean_type,
[TYPE_IFNAME] = &ifname_type,
+ [TYPE_IGMP_TYPE] = &igmp_type_type,
};
const struct datatype *datatype_lookup(enum datatypes type)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 01f5be95..39a3ab04 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -314,6 +314,9 @@ int nft_lex(void *, void *, void *);
%token GATEWAY "gateway"
%token MTU "mtu"
+%token IGMP "igmp"
+%token MRT "mrt"
+
%token OPTIONS "options"
%token IP6 "ip6"
@@ -691,9 +694,9 @@ int nft_lex(void *, void *, void *);
%type <expr> arp_hdr_expr
%destructor { expr_free($$); } arp_hdr_expr
%type <val> arp_hdr_field
-%type <expr> ip_hdr_expr icmp_hdr_expr numgen_expr hash_expr
-%destructor { expr_free($$); } ip_hdr_expr icmp_hdr_expr numgen_expr hash_expr
-%type <val> ip_hdr_field icmp_hdr_field
+%type <expr> ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr
+%destructor { expr_free($$); } ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr
+%type <val> ip_hdr_field icmp_hdr_field igmp_hdr_field
%type <expr> ip6_hdr_expr icmp6_hdr_expr
%destructor { expr_free($$); } ip6_hdr_expr icmp6_hdr_expr
%type <val> ip6_hdr_field icmp6_hdr_field
@@ -3736,6 +3739,13 @@ primary_rhs_expr : symbol_expr { $$ = $1; }
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
+ | IGMP
+ {
+ uint8_t data = IPPROTO_IGMP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
| ICMP6
{
uint8_t data = IPPROTO_ICMPV6;
@@ -4144,6 +4154,7 @@ payload_expr : payload_raw_expr
| arp_hdr_expr
| ip_hdr_expr
| icmp_hdr_expr
+ | igmp_hdr_expr
| ip6_hdr_expr
| icmp6_hdr_expr
| auth_hdr_expr
@@ -4241,6 +4252,18 @@ icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; }
| MTU { $$ = ICMPHDR_MTU; }
;
+igmp_hdr_expr : IGMP igmp_hdr_field
+ {
+ $$ = payload_expr_alloc(&@$, &proto_igmp, $2);
+ }
+ ;
+
+igmp_hdr_field : TYPE { $$ = IGMPHDR_TYPE; }
+ | CHECKSUM { $$ = IGMPHDR_CHECKSUM; }
+ | MRT { $$ = IGMPHDR_MRT; }
+ | GROUP { $$ = IGMPHDR_GROUP; }
+ ;
+
ip6_hdr_expr : IP6 ip6_hdr_field
{
$$ = payload_expr_alloc(&@$, &proto_ip6, $2);
diff --git a/src/payload.c b/src/payload.c
index 6517686c..fab97b11 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -269,7 +269,8 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
return payload_get_get_ll_hdr(ctx);
case PROTO_BASE_TRANSPORT_HDR:
if (expr->payload.desc == &proto_icmp ||
- expr->payload.desc == &proto_icmp6) {
+ expr->payload.desc == &proto_icmp6 ||
+ expr->payload.desc == &proto_igmp) {
const struct proto_desc *desc, *desc_upper;
struct stmt *nstmt;
@@ -281,7 +282,8 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
}
desc_upper = &proto_ip6;
- if (expr->payload.desc == &proto_icmp)
+ if (expr->payload.desc == &proto_icmp ||
+ expr->payload.desc == &proto_igmp)
desc_upper = &proto_ip;
if (payload_add_dependency(ctx, desc, desc_upper,
diff --git a/src/proto.c b/src/proto.c
index d178bf39..f68fb684 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -357,6 +357,55 @@ const struct proto_desc proto_icmp = {
};
/*
+ * IGMP
+ */
+
+#include <netinet/igmp.h>
+
+#ifndef IGMP_V3_MEMBERSHIP_REPORT
+#define IGMP_V3_MEMBERSHIP_REPORT 0x22
+#endif
+
+static const struct symbol_table igmp_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("membership-query", IGMP_MEMBERSHIP_QUERY),
+ SYMBOL("membership-report-v1", IGMP_V1_MEMBERSHIP_REPORT),
+ SYMBOL("membership-report-v2", IGMP_V2_MEMBERSHIP_REPORT),
+ SYMBOL("membership-report-v3", IGMP_V3_MEMBERSHIP_REPORT),
+ SYMBOL("leave-group", IGMP_V2_LEAVE_GROUP),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype igmp_type_type = {
+ .type = TYPE_IGMP_TYPE,
+ .name = "igmp_type",
+ .desc = "IGMP type",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &igmp_type_tbl,
+};
+
+#define IGMPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct igmp, __member)
+#define IGMPHDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct igmp, __member)
+
+const struct proto_desc proto_igmp = {
+ .name = "igmp",
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = IGMPHDR_CHECKSUM,
+ .templates = {
+ [IGMPHDR_TYPE] = IGMPHDR_TYPE("type", &igmp_type_type, igmp_type),
+ [IGMPHDR_MRT] = IGMPHDR_FIELD("mrt", igmp_code),
+ [IGMPHDR_CHECKSUM] = IGMPHDR_FIELD("checksum", igmp_cksum),
+ [IGMPHDR_GROUP] = IGMPHDR_FIELD("group", igmp_group),
+ },
+};
+
+/*
* UDP/UDP-Lite
*/
@@ -591,6 +640,7 @@ const struct proto_desc proto_ip = {
.checksum_key = IPHDR_CHECKSUM,
.protocols = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
+ PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
PROTO_LINK(IPPROTO_ESP, &proto_esp),
PROTO_LINK(IPPROTO_AH, &proto_ah),
@@ -720,6 +770,7 @@ const struct proto_desc proto_ip6 = {
PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
+ PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
},
.templates = {
@@ -784,6 +835,7 @@ const struct proto_desc proto_inet_service = {
PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
+ PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
},
.templates = {
diff --git a/src/scanner.l b/src/scanner.l
index f96944e9..6f83aa11 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -426,6 +426,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"gateway" { return GATEWAY; }
"mtu" { return MTU; }
+"igmp" { return IGMP; }
+"mrt" { return MRT; }
+
"ip6" { return IP6; }
"priority" { return PRIORITY; }
"flowlabel" { return FLOWLABEL; }
diff --git a/tests/py/ip/igmp.t b/tests/py/ip/igmp.t
new file mode 100644
index 00000000..939dcc32
--- /dev/null
+++ b/tests/py/ip/igmp.t
@@ -0,0 +1,25 @@
+# *inet;test-inet
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+
+igmp type membership-query;ok
+igmp type membership-report-v1;ok
+igmp type membership-report-v2;ok
+igmp type membership-report-v3;ok
+igmp type leave-group;ok
+
+igmp type { membership-report-v1, membership-report-v2, membership-report-v3};ok
+igmp type != { membership-report-v1, membership-report-v2, membership-report-v3};ok
+
+igmp checksum 12343;ok
+igmp checksum != 12343;ok
+igmp checksum 11-343;ok
+igmp checksum != 11-343;ok
+igmp checksum { 11-343};ok
+igmp checksum != { 11-343};ok
+igmp checksum { 1111, 222, 343};ok
+igmp checksum != { 1111, 222, 343};ok
+
+igmp mrt 10;ok
+igmp mrt != 10;ok
diff --git a/tests/py/ip/igmp.t.payload b/tests/py/ip/igmp.t.payload
new file mode 100644
index 00000000..1319c324
--- /dev/null
+++ b/tests/py/ip/igmp.t.payload
@@ -0,0 +1,366 @@
+# igmp type membership-query
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# igmp type membership-report-v1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# igmp type membership-report-v2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# igmp type membership-report-v3
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000022 ]
+
+# igmp type leave-group
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# igmp checksum 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003730 ]
+
+# igmp checksum != 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003730 ]
+
+# igmp checksum 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000b00 ]
+ [ cmp lte reg 1 0x00005701 ]
+
+# igmp checksum != 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00000b00 0x00005701 ]
+
+# igmp checksum { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp checksum { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp type membership-query
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# igmp type membership-report-v1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# igmp type membership-report-v2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# igmp type membership-report-v3
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000022 ]
+
+# igmp type leave-group
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp type != { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp checksum 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003730 ]
+
+# igmp checksum != 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003730 ]
+
+# igmp checksum 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000b00 ]
+ [ cmp lte reg 1 0x00005701 ]
+
+# igmp checksum != 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00000b00 0x00005701 ]
+
+# igmp checksum { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp checksum { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp type membership-query
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# igmp type membership-report-v1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# igmp type membership-report-v2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# igmp type membership-report-v3
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000022 ]
+
+# igmp type leave-group
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp type != { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp checksum 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003730 ]
+
+# igmp checksum != 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003730 ]
+
+# igmp checksum 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000b00 ]
+ [ cmp lte reg 1 0x00005701 ]
+
+# igmp checksum != 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00000b00 0x00005701 ]
+
+# igmp checksum { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 11-343}
+__set%d test-ip4 7 size 3
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp checksum { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp mrt 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+
+# igmp mrt != 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp neq reg 1 0x0000000a ]
+