/* * netsniff-ng - the packet sniffing beast * Copyright (C) 2012 Christoph Jaeger * Subject to the GPL, version 2. */ #include #include #include #include "proto.h" #include "csum.h" #include "dissector_eth.h" #include "built_in.h" #include "pkt_buff.h" /* IGMPv0 (RFC-988) */ struct igmp_v0_msg { uint8_t type; uint8_t code; uint16_t checksum; uint32_t identifier; uint32_t group_address; uint64_t access_key; } __packed; /* igmp_v0_msg.type */ #define IGMP_V0_CREATE_GROUP_REQUEST 0x01 #define IGMP_V0_CREATE_GROUP_REPLY 0x02 #define IGMP_V0_JOIN_GROUP_REQUEST 0x03 #define IGMP_V0_JOIN_GROUP_REPLY 0x04 #define IGMP_V0_LEAVE_GROUP_REQUEST 0x05 #define IGMP_V0_LEAVE_GROUP_REPLY 0x06 #define IGMP_V0_CONFIRM_GROUP_REQUEST 0x07 #define IGMP_V0_CONFIRM_GROUP_REPLY 0x08 /* IGMPv1 (RFC-1054/RFC-1112, obsoletes RFC-988) */ struct igmp_v1_msg { union { uint8_t version__type; struct { #if defined(__LITTLE_ENDIAN_BITFIELD) uint8_t type :4, version :4; #elif defined(__BIG_ENDIAN_BITFIELD) uint8_t version :4, type :4; #else # error "Please fix " #endif }; }; uint8_t unused; /* always zero */ uint16_t checksum; uint32_t group_address; } __attribute__((packed)); /* igmp_v1_msg.version__type (!) */ /* IGMP_V1_MEMBERSHIP_QUERY 0x11 */ #define IGMP_V1_MEMBERSHIP_REPORT 0x12 /* IGMPv2 (RFC-2236) */ struct igmp_v2_msg { uint8_t type; uint8_t max_resp_time; uint16_t checksum; uint32_t group_address; } __attribute__((packed)); /* igmp_v2_msg.type */ /* IGMP_V2_MEMBERSHIP_QUERY 0x11 */ #define IGMP_V2_MEMBERSHIP_REPORT 0x16 #define IGMP_V2_LEAVE_GROUP 0x17 /* * RGMP (RFC-3488) * The RGMP message format resembles the IGMPv2 message format. All RGMP * messages are sent with TTL 1, to destination address 224.0.0.25. */ #define RGMP_LEAVE_GROUP 0xFC #define RGMP_JOIN_GROUP 0xFD #define RGMP_BYE 0xFE #define RGMP_HELLO 0xFF /* IGMPv3 (RFC-3376) */ struct igmp_v3_group_record { uint8_t record_type; uint8_t aux_data_len; /* always zero */ uint16_t number_of_sources; uint32_t multicast_address; uint32_t source_addresses[0]; /* auxiliary data (IGMPv3 does not define any) */ } __attribute__((packed)); /* igmp_v3_group_record.record_type */ #define IGMP_V3_MODE_IS_INCLUDE 1 #define IGMP_V3_MODE_IS_EXCLUDE 2 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE 3 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE 4 #define IGMP_V3_ALLOW_NEW_SOURCES 5 #define IGMP_V3_BLOCK_OLD_SOURCES 6 struct igmp_v3_membership_report { uint8_t type; uint8_t reserved1; uint16_t checksum; uint16_t reserved2; uint16_t number_of_group_records; struct igmp_v3_group_record group_records[0]; } __attribute__((packed)); struct igmp_v3_membership_query { uint8_t type; uint8_t max_resp_code; uint16_t checksum; uint32_t group_address; #if defined(__LITTLE_ENDIAN_BITFIELD) uint8_t qrv :3, s_flag :1, :4; #elif defined(__BIG_ENDIAN_BITFIELD) uint8_t :4, s_flag :1, qrv :3; #else # error "Please fix " #endif uint8_t qqic; uint16_t number_of_sources; uint32_t source_addresses[0]; } __attribute__((packed)); #define IGMP_MEMBERSHIP_QUERY 0x11 /* v1/v2/v3 */ #define IGMP_V3_MEMBERSHIP_REPORT 0x22 #define EXP(x) (((x) & 0x70) >> 4) #define MANT(x) ((x) & 0x0F) #define DECODE_MAX_RESP_CODE(x) ((x) < 128 ? (x) : (MANT(x) | 0x10) << (EXP(x) + 3)) #define DECODE_QQIC(x) ((x) < 128 ? (x) : (MANT(x) | 0x10) << (EXP(x) + 3)) static char *friendly_msg_type_name(uint8_t msg_type) { switch (msg_type) { case IGMP_V0_CREATE_GROUP_REQUEST: return "Create Group Request"; case IGMP_V0_CREATE_GROUP_REPLY: return "Create Group Reply"; case IGMP_V0_JOIN_GROUP_REQUEST: return "Join Group Request"; case IGMP_V0_JOIN_GROUP_REPLY: return "Join Group Reply"; case IGMP_V0_LEAVE_GROUP_REQUEST: return "Leave Group Request"; case IGMP_V0_LEAVE_GROUP_REPLY: return "Leave Group Reply"; case IGMP_V0_CONFIRM_GROUP_REQUEST: return "Confirm Group Request"; case IGMP_V0_CONFIRM_GROUP_REPLY: return "Confirm Group Reply"; case IGMP_MEMBERSHIP_QUERY: return "Membership Query"; case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: case IGMP_V3_MEMBERSHIP_REPORT: return "Membership Report"; case IGMP_V2_LEAVE_GROUP: return "Leave Group"; case RGMP_HELLO: return "Hello"; case RGMP_BYE: return "Bye"; case RGMP_JOIN_GROUP: return "Join Group"; case RGMP_LEAVE_GROUP: return "Leave Group"; default: return NULL; } } #define PRINT_FRIENDLY_NAMED_MSG_TYPE(type) \ do { \ if (friendly_msg_type_name(type)) \ tprintf(" Type (0x%.2x, %s)", type, \ friendly_msg_type_name(type)); \ else \ tprintf(" Type (0x%.2x)", type); \ } while (0) static char *friendly_group_rec_type_name(uint8_t rec_type) { switch (rec_type) { case IGMP_V3_MODE_IS_INCLUDE: return "Mode Is Include"; case IGMP_V3_MODE_IS_EXCLUDE: return "Mode Is Exclude"; case IGMP_V3_CHANGE_TO_INCLUDE_MODE: return "Change To Include Mode"; case IGMP_V3_CHANGE_TO_EXCLUDE_MODE: return "Change To Exclude Mode"; case IGMP_V3_ALLOW_NEW_SOURCES: return "Allow New Sources"; case IGMP_V3_BLOCK_OLD_SOURCES: return "Block Old Sources"; default: return NULL; } } static void dissect_igmp_v0(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; static const char *reply_codes[] = { "Request Granted", "Request Denied, No Resources", "Request Denied, Invalid Code", "Request Denied, Invalid Group Address", "Request Denied, Invalid Access Key" }; struct igmp_v0_msg *msg = (struct igmp_v0_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv0"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); switch (msg->type) { case IGMP_V0_CREATE_GROUP_REQUEST: switch (msg->code) { case 0: tprintf(", Code (%u, %s)", msg->code, "Public"); break; case 1: tprintf(", Code (%u, %s)", msg->code, "Private"); break; default: tprintf(", Code (%u)", msg->code); } break; case IGMP_V0_CREATE_GROUP_REPLY: case IGMP_V0_JOIN_GROUP_REPLY: case IGMP_V0_LEAVE_GROUP_REPLY: case IGMP_V0_CONFIRM_GROUP_REPLY: if (msg->code < 5) tprintf(", Code (%u, %s)", msg->code, reply_codes[msg->code]); else tprintf(", Code (%u, Request Pending, Retry In %u Seconds)", msg->code, msg->code); break; default: tprintf(", Code (%u)", msg->code); } csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); tprintf(", Id (%u)", ntohs(msg->identifier)); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(", Access Key (0x%.16lx)", msg->access_key); tprintf(" ]\n"); } static void dissect_igmp_v1(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; struct igmp_v1_msg *msg = (struct igmp_v1_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv1"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->version__type); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(" ]\n"); } static void dissect_igmp_v2(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; struct igmp_v2_msg *msg = (struct igmp_v2_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; switch (msg->type) { case RGMP_HELLO: case RGMP_BYE: case RGMP_JOIN_GROUP: case RGMP_LEAVE_GROUP: tprintf(" [ IGMPv2 (RGMP)"); break; default: tprintf(" [ IGMPv2"); break; } PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); tprintf(", Max Resp Time (%u)", msg->max_resp_time); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(" ]\n"); } static void dissect_igmp_v3_membership_query(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; size_t n; uint16_t csum; uint32_t *src_addr; struct igmp_v3_membership_query *msg = (struct igmp_v3_membership_query *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv3"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); tprintf(", Max Resp Code (0x%.2x => %u)", msg->max_resp_code, DECODE_MAX_RESP_CODE(msg->max_resp_code)); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); /* S Flag (Suppress Router-Side Processing) */ tprintf(", Suppress (%u)", msg->s_flag ? 1 : 0); /* QRV (Querier's Robustness Variable) */ tprintf(", QRV (%u)", msg->qrv); /* QQIC (Querier's Query Interval Code) */ tprintf(", QQIC (0x%.2x => %u)", msg->qqic, DECODE_QQIC(msg->qqic)); tprintf(", Group Addr (%s)", addr); n = ntohs(msg->number_of_sources); tprintf(", Num Src (%zu)", n); if (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr != NULL) { inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", Src Addr (%s", addr); while (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr == NULL) break; inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", %s", addr); } tprintf(")"); } } tprintf(" ]\n"); } static void dissect_igmp_v3_membership_report(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; size_t m, n; uint16_t csum; uint32_t *src_addr; struct igmp_v3_group_record *rec; struct igmp_v3_membership_report *msg = (struct igmp_v3_membership_report *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv3"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); m = ntohs(msg->number_of_group_records); tprintf(", Num Group Rec (%zu)", m); tprintf(" ]\n"); while (m--) { rec = (struct igmp_v3_group_record *) pkt_pull(pkt, sizeof(*rec)); if (rec == NULL) break; tprintf(" [ Group Record"); if (friendly_group_rec_type_name(rec->record_type)) tprintf(" Type (%u, %s)", rec->record_type, friendly_group_rec_type_name(rec->record_type)); else tprintf(" Type (%u)", rec->record_type); n = ntohs(rec->number_of_sources); tprintf(", Num Src (%zu)", n); inet_ntop(AF_INET, &rec->multicast_address, addr, sizeof(addr)); tprintf(", Multicast Addr (%s)", addr); if (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr != NULL) { inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", Src Addr (%s", addr); while (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr == NULL) break; inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", %s", addr); } tprintf(")"); } } tprintf(" ]\n"); } tprintf("\n"); } static void igmp(struct pkt_buff *pkt) { switch (*pkt_peek(pkt)) { case IGMP_V0_CREATE_GROUP_REQUEST: case IGMP_V0_CREATE_GROUP_REPLY: case IGMP_V0_JOIN_GROUP_REQUEST: case IGMP_V0_JOIN_GROUP_REPLY: case IGMP_V0_LEAVE_GROUP_REQUEST: case IGMP_V0_LEAVE_GROUP_REPLY: case IGMP_V0_CONFIRM_GROUP_REQUEST: case IGMP_V0_CONFIRM_GROUP_REPLY: if (pkt_len(pkt) == sizeof(struct igmp_v0_msg)) dissect_igmp_v0(pkt); break; case IGMP_MEMBERSHIP_QUERY: /* v1/v2/v3 */ if (pkt_len(pkt) >= sizeof(struct igmp_v3_membership_query)) dissect_igmp_v3_membership_query(pkt); else if (pkt_len(pkt) == sizeof(struct igmp_v2_msg) && *(pkt_peek(pkt) + 1)) dissect_igmp_v2(pkt); else if (pkt_len(pkt) == sizeof(struct igmp_v1_msg)) dissect_igmp_v1(pkt); break; case IGMP_V1_MEMBERSHIP_REPORT: if (pkt_len(pkt) == sizeof(struct igmp_v1_msg)) dissect_igmp_v1(pkt); break; case RGMP_HELLO: case RGMP_BYE: case RGMP_JOIN_GROUP: case RGMP_LEAVE_GROUP: case IGMP_V2_MEMBERSHIP_REPORT: case IGMP_V2_LEAVE_GROUP: if (pkt_len(pkt) == sizeof(struct igmp_v2_msg)) dissect_igmp_v2(pkt); break; case IGMP_V3_MEMBERSHIP_REPORT: if (pkt_len(pkt) >= sizeof(struct igmp_v3_membership_report)) dissect_igmp_v3_membership_report(pkt); break; } } static void igmp_less(struct pkt_buff *pkt) { int version = -1; switch (*pkt_peek(pkt)) { case IGMP_V0_CREATE_GROUP_REQUEST: case IGMP_V0_CREATE_GROUP_REPLY: case IGMP_V0_JOIN_GROUP_REQUEST: case IGMP_V0_JOIN_GROUP_REPLY: case IGMP_V0_LEAVE_GROUP_REQUEST: case IGMP_V0_LEAVE_GROUP_REPLY: case IGMP_V0_CONFIRM_GROUP_REQUEST: case IGMP_V0_CONFIRM_GROUP_REPLY: if (pkt_len(pkt) == sizeof(struct igmp_v0_msg)) version = 0; break; case IGMP_MEMBERSHIP_QUERY: /* v1/v2/v3 */ if (pkt_len(pkt) >= sizeof(struct igmp_v3_membership_query)) version = 3; else if (pkt_len(pkt) == sizeof(struct igmp_v2_msg) && *(pkt_peek(pkt) + 1)) version = 2; else if (pkt_len(pkt) == sizeof(struct igmp_v1_msg)) version = 1; break; case IGMP_V1_MEMBERSHIP_REPORT: if (pkt_len(pkt) == sizeof(struct igmp_v1_msg)) version = 1; break; case RGMP_HELLO: case RGMP_BYE: case RGMP_JOIN_GROUP: case RGMP_LEAVE_GROUP: case IGMP_V2_MEMBERSHIP_REPORT: case IGMP_V2_LEAVE_GROUP: if (pkt_len(pkt) == sizeof(struct igmp_v2_msg)) version = 2; break; case IGMP_V3_MEMBERSHIP_REPORT: if (pkt_len(pkt) >= sizeof(struct igmp_v3_membership_report)) version = 3; break; } if (version < 0 || version > 3) return; switch (*pkt_peek(pkt)) { case RGMP_HELLO: case RGMP_BYE: case RGMP_JOIN_GROUP: case RGMP_LEAVE_GROUP: tprintf(" IGMPv2 (RGMP)"); break; default: tprintf(" IGMPv%u", version); break; } PRINT_FRIENDLY_NAMED_MSG_TYPE(*pkt_peek(pkt)); } struct protocol igmp_ops = { .key = 0x02, .print_full = igmp, .print_less = igmp_less, }; 166.00 ( 0.00%) 145.00 ( 12.65%) Min free-odr2-64 166.00 ( 0.00%) 146.00 ( 12.05%) Min free-odr2-128 169.00 ( 0.00%) 148.00 ( 12.43%) Min free-odr2-256 170.00 ( 0.00%) 152.00 ( 10.59%) Min free-odr2-512 177.00 ( 0.00%) 156.00 ( 11.86%) Min free-odr2-1024 182.00 ( 0.00%) 162.00 ( 10.99%) Min free-odr2-2048 181.00 ( 0.00%) 160.00 ( 11.60%) Min free-odr2-4096 180.00 ( 0.00%) 159.00 ( 11.67%) Min free-odr3-1 431.00 ( 0.00%) 367.00 ( 14.85%) Min free-odr3-2 306.00 ( 0.00%) 259.00 ( 15.36%) Min free-odr3-4 249.00 ( 0.00%) 208.00 ( 16.47%) Min free-odr3-8 224.00 ( 0.00%) 186.00 ( 16.96%) Min free-odr3-16 208.00 ( 0.00%) 176.00 ( 15.38%) Min free-odr3-32 206.00 ( 0.00%) 174.00 ( 15.53%) Min free-odr3-64 210.00 ( 0.00%) 178.00 ( 15.24%) Min free-odr3-128 215.00 ( 0.00%) 182.00 ( 15.35%) Min free-odr3-256 224.00 ( 0.00%) 189.00 ( 15.62%) Min free-odr3-512 232.00 ( 0.00%) 195.00 ( 15.95%) Min free-odr3-1024 230.00 ( 0.00%) 195.00 ( 15.22%) Min free-odr3-2048 229.00 ( 0.00%) 193.00 ( 15.72%) Min free-odr4-1 561.00 ( 0.00%) 439.00 ( 21.75%) Min free-odr4-2 418.00 ( 0.00%) 318.00 ( 23.92%) Min free-odr4-4 339.00 ( 0.00%) 269.00 ( 20.65%) Min free-odr4-8 299.00 ( 0.00%) 239.00 ( 20.07%) Min free-odr4-16 289.00 ( 0.00%) 234.00 ( 19.03%) Min free-odr4-32 291.00 ( 0.00%) 235.00 ( 19.24%) Min free-odr4-64 298.00 ( 0.00%) 238.00 ( 20.13%) Min free-odr4-128 308.00 ( 0.00%) 251.00 ( 18.51%) Min free-odr4-256 321.00 ( 0.00%) 267.00 ( 16.82%) Min free-odr4-512 327.00 ( 0.00%) 269.00 ( 17.74%) Min free-odr4-1024 326.00 ( 0.00%) 271.00 ( 16.87%) Min total-odr0-1 644.00 ( 0.00%) 494.00 ( 23.29%) Min total-odr0-2 466.00 ( 0.00%) 356.00 ( 23.61%) Min total-odr0-4 376.00 ( 0.00%) 291.00 ( 22.61%) Min total-odr0-8 328.00 ( 0.00%) 251.00 ( 23.48%) Min total-odr0-16 304.00 ( 0.00%) 234.00 ( 23.03%) Min total-odr0-32 289.00 ( 0.00%) 224.00 ( 22.49%) Min total-odr0-64 282.00 ( 0.00%) 218.00 ( 22.70%) Min total-odr0-128 280.00 ( 0.00%) 216.00 ( 22.86%) Min total-odr0-256 310.00 ( 0.00%) 243.00 ( 21.61%) Min total-odr0-512 329.00 ( 0.00%) 273.00 ( 17.02%) Min total-odr0-1024 346.00 ( 0.00%) 290.00 ( 16.18%) Min total-odr0-2048 357.00 ( 0.00%) 304.00 ( 14.85%) Min total-odr0-4096 367.00 ( 0.00%) 315.00 ( 14.17%) Min total-odr0-8192 372.00 ( 0.00%) 317.00 ( 14.78%) Min total-odr0-16384 373.00 ( 0.00%) 319.00 ( 14.48%) Min total-odr1-1 838.00 ( 0.00%) 739.00 ( 11.81%) Min total-odr1-2 619.00 ( 0.00%) 543.00 ( 12.28%) Min total-odr1-4 495.00 ( 0.00%) 433.00 ( 12.53%) Min total-odr1-8 440.00 ( 0.00%) 382.00 ( 13.18%) Min total-odr1-16 407.00 ( 0.00%) 353.00 ( 13.27%) Min total-odr1-32 398.00 ( 0.00%) 341.00 ( 14.32%) Min total-odr1-64 389.00 ( 0.00%) 336.00 ( 13.62%) Min total-odr1-128 392.00 ( 0.00%) 341.00 ( 13.01%) Min total-odr1-256 391.00 ( 0.00%) 344.00 ( 12.02%) Min total-odr1-512 396.00 ( 0.00%) 349.00 ( 11.87%) Min total-odr1-1024 402.00 ( 0.00%) 357.00 ( 11.19%) Min total-odr1-2048 409.00 ( 0.00%) 364.00 ( 11.00%) Min total-odr1-4096 414.00 ( 0.00%) 366.00 ( 11.59%) Min total-odr1-8192 417.00 ( 0.00%) 369.00 ( 11.51%) Min total-odr2-1 921.00 ( 0.00%) 1210.00 (-31.38%) Min total-odr2-2 682.00 ( 0.00%) 576.00 ( 15.54%) Min total-odr2-4 547.00 ( 0.00%) 616.00 (-12.61%) Min total-odr2-8 483.00 ( 0.00%) 406.00 ( 15.94%) Min total-odr2-16 449.00 ( 0.00%) 376.00 ( 16.26%) Min total-odr2-32 437.00 ( 0.00%) 366.00 ( 16.25%) Min total-odr2-64 431.00 ( 0.00%) 363.00 ( 15.78%) Min total-odr2-128 433.00 ( 0.00%) 365.00 ( 15.70%) Min total-odr2-256 434.00 ( 0.00%) 371.00 ( 14.52%) Min total-odr2-512 446.00 ( 0.00%) 379.00 ( 15.02%) Min total-odr2-1024 461.00 ( 0.00%) 392.00 ( 14.97%) Min total-odr2-2048 464.00 ( 0.00%) 395.00 ( 14.87%) Min total-odr2-4096 465.00 ( 0.00%) 398.00 ( 14.41%) Min total-odr3-1 1060.00 ( 0.00%) 872.00 ( 17.74%) Min total-odr3-2 778.00 ( 0.00%) 633.00 ( 18.64%) Min total-odr3-4 632.00 ( 0.00%) 510.00 ( 19.30%) Min total-odr3-8 565.00 ( 0.00%) 452.00 ( 20.00%) Min total-odr3-16 524.00 ( 0.00%) 424.00 ( 19.08%) Min total-odr3-32 514.00 ( 0.00%) 415.00 ( 19.26%) Min total-odr3-64 515.00 ( 0.00%) 419.00 ( 18.64%) Min total-odr3-128 523.00 ( 0.00%) 426.00 ( 18.55%) Min total-odr3-256 541.00 ( 0.00%) 438.00 ( 19.04%) Min total-odr3-512 559.00 ( 0.00%) 451.00 ( 19.32%) Min total-odr3-1024 561.00 ( 0.00%) 456.00 ( 18.72%) Min total-odr3-2048 562.00 ( 0.00%) 459.00 ( 18.33%) Min total-odr4-1 1328.00 ( 0.00%) 1011.00 ( 23.87%) Min total-odr4-2 997.00 ( 0.00%) 747.00 ( 25.08%) Min total-odr4-4 813.00 ( 0.00%) 615.00 ( 24.35%) Min total-odr4-8 721.00 ( 0.00%) 550.00 ( 23.72%) Min total-odr4-16 689.00 ( 0.00%) 529.00 ( 23.22%) Min total-odr4-32 683.00 ( 0.00%) 528.00 ( 22.69%) Min total-odr4-64 692.00 ( 0.00%) 531.00 ( 23.27%) Min total-odr4-128 713.00 ( 0.00%) 556.00 ( 22.02%) Min total-odr4-256 738.00 ( 0.00%) 586.00 ( 20.60%) Min total-odr4-512 753.00 ( 0.00%) 595.00 ( 20.98%) Min total-odr4-1024 752.00 ( 0.00%) 600.00 ( 20.21%) This patch (of 27): order-0 pages by definition cannot be compound so avoid the check in the fast path for those pages. [akpm@linux-foundation.org: use unlikely(order) in free_pages_prepare(), per Vlastimil] Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/page_alloc.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c