diff --git a/cps/kni.c b/cps/kni.c index d6e15fa69..dfe68dffa 100644 --- a/cps/kni.c +++ b/cps/kni.c @@ -2155,7 +2155,8 @@ kni_process_nd(struct cps_config *cps_conf, struct gatekeeper_if *iface, icmpv6_hdr = rte_pktmbuf_mtod_offset(buf, struct icmpv6_hdr *, sizeof(*eth_hdr) + sizeof(struct rte_ipv6_hdr)); - if (icmpv6_hdr->type == ND_NEIGHBOR_ADVERTISEMENT) { + if (icmpv6_hdr->type == ND_NEIGHBOR_ADVERTISEMENT_TYPE && + icmpv6_hdr->code == ND_NEIGHBOR_ADVERTISEMENT_CODE) { CPS_LOG(NOTICE, "ND Advertisement packet received from KNI attached to %s iface\n", iface->name); goto out; diff --git a/cps/main.c b/cps/main.c index d37370918..73324be2a 100644 --- a/cps/main.c +++ b/cps/main.c @@ -206,8 +206,8 @@ send_nd_reply_kni(struct cps_config *cps_conf, struct cps_nd_req *nd) /* Set-up ICMPv6 header. */ icmpv6_hdr = (struct icmpv6_hdr *)&ipv6_hdr[1]; - icmpv6_hdr->type = ND_NEIGHBOR_ADVERTISEMENT; - icmpv6_hdr->code = 0; + icmpv6_hdr->type = ND_NEIGHBOR_ADVERTISEMENT_TYPE; + icmpv6_hdr->code = ND_NEIGHBOR_ADVERTISEMENT_CODE; icmpv6_hdr->cksum = 0; /* Calculated below. */ /* Set up ND Advertisement header with target LL addr option. */ @@ -375,8 +375,8 @@ process_ingress(struct gatekeeper_if *iface, struct rte_kni *kni, } static int -pkt_is_nd(struct gatekeeper_if *iface, struct rte_ether_hdr *eth_hdr, - uint16_t pkt_len) +cps_pkt_is_nd_neighbor(struct gatekeeper_if *iface, + struct rte_ether_hdr *eth_hdr, uint16_t pkt_len) { struct rte_ipv6_hdr *ipv6_hdr; struct icmpv6_hdr *icmpv6_hdr; @@ -392,11 +392,10 @@ pkt_is_nd(struct gatekeeper_if *iface, struct rte_ether_hdr *eth_hdr, /* * Make sure this is an ND neighbor message and that it was * sent by us (our global address, link-local address, or - * either of the solicited-node multicast addresses. + * either of the solicited-node multicast addresses). */ icmpv6_hdr = (struct icmpv6_hdr *)&ipv6_hdr[1]; - return (icmpv6_hdr->type == ND_NEIGHBOR_SOLICITATION || - icmpv6_hdr->type == ND_NEIGHBOR_ADVERTISEMENT) && + return pkt_is_nd_neighbor(icmpv6_hdr->type, icmpv6_hdr->code) && (ipv6_addrs_equal(ipv6_hdr->src_addr, iface->ll_ip6_addr.s6_addr) || ipv6_addrs_equal(ipv6_hdr->src_addr, @@ -432,7 +431,7 @@ process_egress(struct cps_config *cps_conf, struct gatekeeper_if *iface, break; case RTE_ETHER_TYPE_IPV6: { uint16_t pkt_len = rte_pktmbuf_data_len(bufs[i]); - if (pkt_is_nd(iface, eth_hdr, pkt_len)) { + if (cps_pkt_is_nd_neighbor(iface, eth_hdr, pkt_len)) { /* Intercept ND packet and handle it. */ kni_process_nd(cps_conf, iface, bufs[i], eth_hdr, pkt_len); diff --git a/include/gatekeeper_acl.h b/include/gatekeeper_acl.h index 59c4bbf42..840f60be7 100644 --- a/include/gatekeeper_acl.h +++ b/include/gatekeeper_acl.h @@ -107,7 +107,6 @@ enum { DST_FIELD_IPV4, SRCP_FIELD_IPV4, DSTP_FIELD_IPV4, - TYPE_FIELD_ICMP, NUM_FIELDS_IPV4, }; diff --git a/include/gatekeeper_lls.h b/include/gatekeeper_lls.h index e1fa89986..4ffb6a846 100644 --- a/include/gatekeeper_lls.h +++ b/include/gatekeeper_lls.h @@ -46,12 +46,10 @@ enum lls_req_ty { LLS_REQ_PUT, /* Request to handle ARP packets received from another block. */ LLS_REQ_ARP, - /* Request to handle ND packets received from another block. */ - LLS_REQ_ND, - /* Request to handle ICMP ping packets received from another block. */ - LLS_REQ_PING, - /* Request to handle ICMPv6 ping packets received from another block. */ - LLS_REQ_PING6, + /* Request to handle ICMP packets received from another block. */ + LLS_REQ_ICMP, + /* Request to handle ICMPv6 packets received from another block. */ + LLS_REQ_ICMP6, }; /* Replies that come from the LLS block. */ @@ -370,52 +368,99 @@ struct nd_opt_lladdr { sizeof(struct nd_opt_lladdr)) /* - * Minimum size of an IPv4 ping packet. + * Minimum size of an IPv4 ICMP packet. * - * Note that, according to RFC pages 13 and 14, - * both the ICMP Echo request header and Echo reply header require 8 bytes. + * Note that the minimum ICMP header size is 8 bytes (RFC 792), + * but DPDK's struct rte_icmp_hdr includes other fields. */ #define ICMP_PKT_MIN_LEN(l2_len) (l2_len + sizeof(struct rte_ipv4_hdr) + 8) /* - * Minimum size of an IPv6 ping packet. + * Minimum size of an ICMPv6 packet. * - * Note that, according to RFC 4443 section 4.1 and section 4.2, - * both the ICMPv6 Echo request header and Echo reply header require 8 bytes. + * Note that the minimum ICMPv6 header size is the four bytes + * defined in struct icmpv6_hdr (RFC 4443). */ -#define ICMPV6_PKT_MIN_LEN(l2_len) (l2_len + sizeof(struct rte_ipv6_hdr) + 8) +#define ICMPV6_PKT_MIN_LEN(l2_len) (l2_len + sizeof(struct rte_ipv6_hdr) + \ + sizeof(struct icmpv6_hdr)) /* Flags for Neighbor Advertisements. */ #define LLS_ND_NA_SOLICITED 0x40000000 #define LLS_ND_NA_OVERRIDE 0x20000000 +/* The IPv6 all nodes multicast address. */ +static const struct in6_addr ip6_allnodes_mc_addr = { + .s6_addr = { + 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } +}; + /* - * Supported IPv4 ping packets via the type and code fields - * in struct icmp_hdr. + * ICMP message types. */ + +/* ICMP Echo Request. */ #define ICMP_ECHO_REQUEST_TYPE (8) #define ICMP_ECHO_REQUEST_CODE (0) -/* ICMP type and code fields for echo reply messages. */ +/* ICMP Echo Reply. */ #define ICMP_ECHO_REPLY_TYPE (0) #define ICMP_ECHO_REPLY_CODE (0) +/* ICMP Destination Unreachable, Fragmentation required, and DF flag set. */ +#define ICMP_DEST_UNREACHABLE_TYPE (3) +#define ICMP_FRAG_REQ_DF_CODE (4) + /* - * Supported IPv6 ping packets via the type and code fields - * in struct icmpv6_hdr. + * ICMPv6 message types. */ + +/* ICMPv6 Echo Request. */ #define ICMPV6_ECHO_REQUEST_TYPE (128) #define ICMPV6_ECHO_REQUEST_CODE (0) -/* ICMPv6 type and code fields for echo reply messages. */ +/* ICMPv6 Echo Reply. */ #define ICMPV6_ECHO_REPLY_TYPE (129) #define ICMPV6_ECHO_REPLY_CODE (0) -/* Supported IPv6 ND packets via the type field in struct icmpv6_hdr. */ -#define ND_ROUTER_SOLICITATION (133) -#define ND_ROUTER_ADVERTISEMENT (134) -#define ND_NEIGHBOR_SOLICITATION (135) -#define ND_NEIGHBOR_ADVERTISEMENT (136) +/* ICMPv6 Packet Too Big. */ +#define ICMPV6_PACKET_TOO_BIG_TYPE (2) +#define ICMPV6_PACKET_TOO_BIG_CODE (0) + +/* ICMPv6 Neighbor Discovery Router Solicitation. */ +#define ND_ROUTER_SOLICITATION_TYPE (133) +#define ND_ROUTER_SOLICITATION_CODE (0) + +/* ICMPv6 Neighbor Discovery Router Advertisement. */ +#define ND_ROUTER_ADVERTISEMENT_TYPE (134) +#define ND_ROUTER_ADVERTISEMENT_CODE (0) + +/* ICMPv6 Neighbor Discovery Neighbor Solicitation. */ +#define ND_NEIGHBOR_SOLICITATION_TYPE (135) +#define ND_NEIGHBOR_SOLICITATION_CODE (0) + +/* ICMPv6 Neighbor Discovery Neighbor Advertisement. */ +#define ND_NEIGHBOR_ADVERTISEMENT_TYPE (136) +#define ND_NEIGHBOR_ADVERTISEMENT_CODE (0) + +static inline int +pkt_is_nd_router(uint8_t type, uint8_t code) +{ + return (type == ND_ROUTER_SOLICITATION_TYPE && + code == ND_ROUTER_SOLICITATION_CODE) || + (type == ND_ROUTER_ADVERTISEMENT_TYPE && + code == ND_ROUTER_ADVERTISEMENT_CODE); +} + +static inline int +pkt_is_nd_neighbor(uint8_t type, uint8_t code) +{ + return (type == ND_NEIGHBOR_SOLICITATION_TYPE && + code == ND_NEIGHBOR_SOLICITATION_CODE) || + (type == ND_NEIGHBOR_ADVERTISEMENT_TYPE && + code == ND_NEIGHBOR_ADVERTISEMENT_CODE); +} static inline int arp_enabled(struct lls_config *lls_conf) diff --git a/lib/acl.c b/lib/acl.c index 94ddd71af..f4b403dc3 100644 --- a/lib/acl.c +++ b/lib/acl.c @@ -209,15 +209,6 @@ struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { .input_index = PORTS_INPUT_IPV4, .offset = sizeof(struct rte_ipv4_hdr) + sizeof(uint16_t), }, - { - /* Enforce grouping into four bytes. */ - .type = RTE_ACL_FIELD_TYPE_BITMASK, - .size = sizeof(uint32_t), - .field_index = TYPE_FIELD_ICMP, - .input_index = TYPE_INPUT_ICMP, - .offset = sizeof(struct rte_ipv4_hdr) + - offsetof(struct rte_icmp_hdr, icmp_type), - }, }; /* diff --git a/lls/cache.c b/lls/cache.c index a701e9f16..17d376903 100644 --- a/lls/cache.c +++ b/lls/cache.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -332,8 +333,8 @@ icmp_cksum(void *buf, unsigned int size) return (unsigned short)(~cksum); } -static int -xmit_icmp_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) +static void +xmit_icmp_ping_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) { struct rte_ether_addr eth_addr_tmp; struct rte_ether_hdr *icmp_eth = rte_pktmbuf_mtod(pkt, @@ -359,13 +360,6 @@ xmit_icmp_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) */ icmp_ipv4 = (struct rte_ipv4_hdr *)pkt_out_skip_l2(iface, icmp_eth); - if (rte_ipv4_frag_pkt_is_fragmented(icmp_ipv4)) { - LLS_LOG(WARNING, - "Received fragmented ping packets destined to this server at %s\n", - __func__); - return -1; - } - icmp_ipv4->time_to_live = IP_DEFTTL; ip_addr_tmp = icmp_ipv4->src_addr; icmp_ipv4->src_addr = icmp_ipv4->dst_addr; @@ -375,9 +369,6 @@ xmit_icmp_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) pkt->l3_len = ipv4_hdr_len(icmp_ipv4); set_ipv4_checksum(iface, pkt, icmp_ipv4); - if (icmp_ipv4->next_proto_id != IPPROTO_ICMP) - return -1; - /* * According to RFC 792 page 14: * @@ -395,15 +386,118 @@ xmit_icmp_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) icmph->icmp_code = ICMP_ECHO_REPLY_CODE; icmph->icmp_cksum = 0; icmph->icmp_cksum = icmp_cksum(icmph, sizeof(*icmph)); +} - return 0; +static void +process_ping_pkts(struct rte_mbuf **pkts, unsigned int num_pkts, + struct lls_config *lls_conf, struct gatekeeper_if *iface, + void (*xmit_reply_fn)(struct gatekeeper_if *, struct rte_mbuf *)) +{ + uint16_t tx_queue; + struct token_bucket_ratelimit_state *rs; + unsigned int i; + unsigned int num_granted_pkts; + + if (iface == &lls_conf->net->front) { + tx_queue = lls_conf->tx_queue_front; + rs = &lls_conf->front_icmp_rs; + } else { + tx_queue = lls_conf->tx_queue_back; + rs = &lls_conf->back_icmp_rs; + } + + num_granted_pkts = tb_ratelimit_allow_n(num_pkts, rs); + + for (i = 0; i < num_granted_pkts; i++) + (*xmit_reply_fn)(iface, pkts[i]); + send_pkts(iface->id, tx_queue, num_granted_pkts, pkts); + + /* XXX #435: Adopt rte_pktmbuf_free_bulk() when DPDK is updated. */ + for (i = num_granted_pkts; i < num_pkts; i++) + rte_pktmbuf_free(pkts[i]); } -static int -xmit_icmpv6_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) +static void +process_icmp_pkts(struct lls_config *lls_conf, struct lls_icmp_req *icmp) +{ + struct rte_mbuf *ping_pkts[icmp->num_pkts]; + unsigned int num_ping_pkts = 0; + int i; + + for (i = 0; i < icmp->num_pkts; i++) { + struct rte_mbuf *pkt = icmp->pkts[i]; + struct rte_ether_hdr *eth_hdr = + rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); + struct rte_ipv4_hdr *ip4hdr; + struct rte_icmp_hdr *icmphdr; + size_t l2_len = pkt_in_l2_hdr_len(pkt); + char src_ip_buf[INET_ADDRSTRLEN]; + const char *src_ip_or_err; + + pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip4hdr); + if (unlikely(pkt->data_len < (ICMP_PKT_MIN_LEN(l2_len) + + ipv4_hdr_len(ip4hdr) - sizeof(*ip4hdr)))) { + rte_pktmbuf_free(pkt); + continue; + } + + /* + * We must check whether the packet is fragmented here because + * although match_icmp() checks for it, the ACL rule does not. + */ + if (unlikely(rte_ipv4_frag_pkt_is_fragmented(ip4hdr))) { + src_ip_or_err = inet_ntop(AF_INET, &ip4hdr->src_addr, + src_ip_buf, sizeof(src_ip_buf)); + if (unlikely(!src_ip_or_err)) + src_ip_or_err = "(could not convert IP to string)"; + + LLS_LOG(WARNING, + "Received fragmented ICMP packets destined to this server on the %s interface from source IP %s\n", + icmp->iface->name, src_ip_or_err); + rte_pktmbuf_free(pkt); + continue; + } + + /* + * We don't need to make sure the next header is ICMP + * because both match_icmp() and the ACL rule already check. + */ + + icmphdr = (struct rte_icmp_hdr *)ipv4_skip_exthdr(ip4hdr); + + if (icmphdr->icmp_type == ICMP_ECHO_REQUEST_TYPE && + icmphdr->icmp_code == ICMP_ECHO_REQUEST_CODE) { + ping_pkts[num_ping_pkts++] = pkt; + continue; + } + + src_ip_or_err = inet_ntop(AF_INET, &ip4hdr->src_addr, + src_ip_buf, sizeof(src_ip_buf)); + if (unlikely(!src_ip_or_err)) + src_ip_or_err = "(could not convert IP to string)"; + + if (icmphdr->icmp_type == ICMP_DEST_UNREACHABLE_TYPE && + icmphdr->icmp_code == ICMP_FRAG_REQ_DF_CODE) { + LLS_LOG(ERR, "Received \"Fragmentation required, and DF flag set\" ICMP packet on the %s interface from source IP %s; check MTU along path\n", + icmp->iface->name, src_ip_or_err); + } else { + LLS_LOG(INFO, "Received ICMP packet with type %hhu and code %hhu on the %s interface from source IP %s\n", + icmphdr->icmp_type, icmphdr->icmp_code, + icmp->iface->name, src_ip_or_err); + } + rte_pktmbuf_free(pkt); + } + + if (num_ping_pkts > 0) + process_ping_pkts(ping_pkts, num_ping_pkts, + lls_conf, icmp->iface, xmit_icmp_ping_reply); +} + +static void +xmit_icmp6_ping_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) { /* - * The icmpv6 header offset in terms of the + * The ICMPv6 header offset in terms of the * beginning of the IPv6 header. */ int icmpv6_offset; @@ -426,13 +520,6 @@ xmit_icmpv6_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) /* Set-up IPv6 header. */ icmp_ipv6 = (struct rte_ipv6_hdr *)pkt_out_skip_l2(iface, icmp_eth); - if (rte_ipv6_frag_get_ipv6_fragment_header(icmp_ipv6) != NULL) { - LLS_LOG(WARNING, - "Received fragmented ping6 packets destined to this server at %s\n", - __func__); - return -1; - } - /* * The IP Hop Limit field must be 255 as required by * RFC 4861, sections 7.1.1 and 7.1.2. @@ -455,14 +542,18 @@ xmit_icmpv6_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) rte_memcpy(icmp_ipv6->src_addr, iface->ip6_addr.s6_addr, sizeof(icmp_ipv6->src_addr)); - /* Set-up ICMPv6 header. */ + /* + * Set-up ICMPv6 header. + * + * We don't need to make sure the next header is ICMPv6 + * or verify the format of the extension headers. See + * process_icmpv6_pkts() and match_icmp6(). + */ icmpv6_offset = ipv6_skip_exthdr(icmp_ipv6, pkt->data_len - l2_len, &nexthdr); - if (icmpv6_offset < 0 || nexthdr != IPPROTO_ICMPV6) - return -1; - - icmpv6_hdr = - (struct icmpv6_hdr *)((uint8_t *)icmp_ipv6 + icmpv6_offset); + RTE_VERIFY(icmpv6_offset >= 0); + icmpv6_hdr = (struct icmpv6_hdr *)((uint8_t *)icmp_ipv6 + + icmpv6_offset); icmpv6_hdr->type = ICMPV6_ECHO_REPLY_TYPE; icmpv6_hdr->code = ICMPV6_ECHO_REPLY_CODE; @@ -477,8 +568,111 @@ xmit_icmpv6_reply(struct gatekeeper_if *iface, struct rte_mbuf *pkt) */ icmpv6_hdr->cksum = rte_ipv6_icmpv6_cksum(icmp_ipv6, icmpv6_hdr); +} - return 0; +static void +process_icmp6_pkts(struct lls_config *lls_conf, struct lls_icmp6_req *icmp6) +{ + struct rte_mbuf *ping6_pkts[icmp6->num_pkts]; + unsigned int num_ping6_pkts = 0; + int i; + + for (i = 0; i < icmp6->num_pkts; i++) { + struct rte_mbuf *pkt = icmp6->pkts[i]; + /* + * The ICMPv6 header offset in terms of the + * beginning of the IPv6 header. + */ + int icmpv6_offset; + uint8_t nexthdr; + struct rte_ether_hdr *eth_hdr = + rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); + struct rte_ipv6_hdr *ip6hdr; + struct icmpv6_hdr *icmp6_hdr; + size_t l2_len = pkt_in_l2_hdr_len(pkt); + char src_ip_buf[INET6_ADDRSTRLEN]; + const char *src_ip_or_err; + + pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip6hdr); + + /* + * We must check whether the packet is fragmented here because + * although match_icmp6() checks for it, the ACL rule does not. + */ + if (unlikely(rte_ipv6_frag_get_ipv6_fragment_header(ip6hdr) != + NULL)) { + src_ip_or_err = inet_ntop(AF_INET6, &ip6hdr->src_addr, + src_ip_buf, sizeof(src_ip_buf)); + if (unlikely(!src_ip_or_err)) + src_ip_or_err = "(could not convert IP to string)"; + + LLS_LOG(WARNING, + "Received fragmented ICMPv6 packets destined to this server on the %s interface from source IP %s\n", + icmp6->iface->name, src_ip_or_err); + rte_pktmbuf_free(pkt); + continue; + } + + /* + * We don't need to make sure the next header is ICMPv6 + * because both match_icmp6() and the ACL rule already check. + * We also don't need to verify that the header extensions + * were not malformed, since if there were extension headers + * then match_icmp6() would have already verified them. But + * we can at least add an assertion to catch bugs. + */ + + icmpv6_offset = ipv6_skip_exthdr(ip6hdr, + pkt->data_len - l2_len, &nexthdr); + RTE_VERIFY(icmpv6_offset >= 0); + icmp6_hdr = (struct icmpv6_hdr *)((uint8_t *)ip6hdr + + icmpv6_offset); + + /* Silently drop ND Router messages to avoid cluttering log. */ + if (pkt_is_nd_router(icmp6_hdr->type, icmp6_hdr->code)) { + rte_pktmbuf_free(pkt); + continue; + } + + /* No other types should have the all nodes multicast addr. */ + if (memcmp(ip6hdr->dst_addr, &ip6_allnodes_mc_addr, + sizeof(ip6_allnodes_mc_addr)) == 0) { + rte_pktmbuf_free(pkt); + continue; + } + + if (icmp6_hdr->type == ICMPV6_ECHO_REQUEST_TYPE && + icmp6_hdr->code == ICMPV6_ECHO_REQUEST_CODE) { + ping6_pkts[num_ping6_pkts++] = pkt; + continue; + } + + if (pkt_is_nd_neighbor(icmp6_hdr->type, icmp6_hdr->code)) { + if (process_nd(lls_conf, icmp6->iface, pkt) == -1) + rte_pktmbuf_free(pkt); + continue; + } + + src_ip_or_err = inet_ntop(AF_INET6, &ip6hdr->src_addr, + src_ip_buf, sizeof(src_ip_buf)); + if (unlikely(!src_ip_or_err)) + src_ip_or_err = "(could not convert IP to string)"; + + if (icmp6_hdr->type == ICMPV6_PACKET_TOO_BIG_TYPE && + icmp6_hdr->code == ICMPV6_PACKET_TOO_BIG_CODE) { + LLS_LOG(ERR, "Received \"Packet Too Big\" ICMPv6 packet on %s interface from source IP %s; check MTU along path\n", + icmp6->iface->name, src_ip_or_err); + } else { + LLS_LOG(INFO, "Received ICMPv6 packet with type %hhu and code %hhu on %s interface from source IP %s\n", + icmp6_hdr->type, icmp6_hdr->code, + icmp6->iface->name, src_ip_or_err); + } + rte_pktmbuf_free(pkt); + } + + if (num_ping6_pkts > 0) + process_ping_pkts(ping6_pkts, num_ping6_pkts, + lls_conf, icmp6->iface, xmit_icmp6_ping_reply); } unsigned int @@ -521,84 +715,12 @@ lls_process_reqs(struct lls_config *lls_conf) } break; } - case LLS_REQ_ND: { - struct lls_nd_req *nd = &reqs[i]->u.nd; - int i; - for (i = 0; i < nd->num_pkts; i++) { - if (process_nd(lls_conf, nd->iface, - nd->pkts[i]) == -1) - rte_pktmbuf_free(nd->pkts[i]); - } - break; - } - case LLS_REQ_PING: { - struct lls_ping_req *ping = &reqs[i]->u.ping; - uint16_t tx_queue; - struct token_bucket_ratelimit_state *rs; - int num_granted_pkts; - int i; - int num_reply = 0; - - if (ping->iface == &lls_conf->net->front) { - tx_queue = lls_conf->tx_queue_front; - rs = &lls_conf->front_icmp_rs; - } else { - tx_queue = lls_conf->tx_queue_back; - rs = &lls_conf->back_icmp_rs; - } - - num_granted_pkts = - tb_ratelimit_allow_n(ping->num_pkts, rs); - - for (i = 0; i < ping->num_pkts; i++) { - if (num_reply >= num_granted_pkts || - xmit_icmp_reply(ping->iface, - ping->pkts[i]) != 0) { - rte_pktmbuf_free(ping->pkts[i]); - continue; - } - ping->pkts[num_reply++] = ping->pkts[i]; - } - - send_pkts(ping->iface->id, tx_queue, - num_reply, ping->pkts); - + case LLS_REQ_ICMP: + process_icmp_pkts(lls_conf, &reqs[i]->u.icmp); break; - } - case LLS_REQ_PING6: { - struct lls_ping6_req *ping6 = &reqs[i]->u.ping6; - uint16_t tx_queue; - struct token_bucket_ratelimit_state *rs; - int num_granted_pkts; - int i; - int num_reply = 0; - - if (ping6->iface == &lls_conf->net->front) { - tx_queue = lls_conf->tx_queue_front; - rs = &lls_conf->front_icmp_rs; - } else { - tx_queue = lls_conf->tx_queue_back; - rs = &lls_conf->back_icmp_rs; - } - - num_granted_pkts = - tb_ratelimit_allow_n(ping6->num_pkts, rs); - - for (i = 0; i < ping6->num_pkts; i++) { - if (num_reply >= num_granted_pkts || - xmit_icmpv6_reply(ping6->iface, - ping6->pkts[i]) != 0) { - rte_pktmbuf_free(ping6->pkts[i]); - continue; - } - ping6->pkts[num_reply++] = ping6->pkts[i]; - } - - send_pkts(ping6->iface->id, tx_queue, - num_reply, ping6->pkts); - + case LLS_REQ_ICMP6: + process_icmp6_pkts(lls_conf, &reqs[i]->u.icmp6); break; - } default: LLS_LOG(ERR, "Unrecognized request type (%d)\n", reqs[i]->ty); @@ -638,27 +760,20 @@ lls_req(enum lls_req_ty ty, void *req_arg) sizeof(arp_req->pkts[0]) * arp_req->num_pkts); break; } - case LLS_REQ_ND: { - struct lls_nd_req *nd_req = (struct lls_nd_req *)req_arg; - req->u.nd = *nd_req; - rte_memcpy(req->u.nd.pkts, nd_req->pkts, - sizeof(nd_req->pkts[0]) * nd_req->num_pkts); - break; - } - case LLS_REQ_PING: { - struct lls_ping_req *ping_req = - (struct lls_ping_req *)req_arg; - req->u.ping = *ping_req; - rte_memcpy(req->u.ping.pkts, ping_req->pkts, - sizeof(ping_req->pkts[0]) * ping_req->num_pkts); + case LLS_REQ_ICMP: { + struct lls_icmp_req *icmp_req = + (struct lls_icmp_req *)req_arg; + req->u.icmp = *icmp_req; + rte_memcpy(req->u.icmp.pkts, icmp_req->pkts, + sizeof(icmp_req->pkts[0]) * icmp_req->num_pkts); break; } - case LLS_REQ_PING6: { - struct lls_ping6_req *ping6_req = - (struct lls_ping6_req *)req_arg; - req->u.ping6 = *ping6_req; - rte_memcpy(req->u.ping6.pkts, ping6_req->pkts, - sizeof(ping6_req->pkts[0]) * ping6_req->num_pkts); + case LLS_REQ_ICMP6: { + struct lls_icmp6_req *icmp6_req = + (struct lls_icmp6_req *)req_arg; + req->u.icmp6 = *icmp6_req; + rte_memcpy(req->u.icmp6.pkts, icmp6_req->pkts, + sizeof(icmp6_req->pkts[0]) * icmp6_req->num_pkts); break; } default: diff --git a/lls/cache.h b/lls/cache.h index 43a873dbf..3fb2c2900 100644 --- a/lls/cache.h +++ b/lls/cache.h @@ -69,27 +69,27 @@ struct lls_nd_req { struct rte_mbuf *pkts[0]; }; -/* Information needed to submit ICMP ping packets to the LLS block. */ -struct lls_ping_req { +/* Information needed to submit ICMP packets to the LLS block. */ +struct lls_icmp_req { /* Number of packets stored in @pkts. */ int num_pkts; /* Interface that received @pkt. */ struct gatekeeper_if *iface; - /* ICMP ping packets. */ + /* ICMP packets. */ struct rte_mbuf *pkts[0]; }; -/* Information needed to submit ICMPv6 ping packets to the LLS block. */ -struct lls_ping6_req { +/* Information needed to submit ICMPv6 packets to the LLS block. */ +struct lls_icmp6_req { /* Number of packets stored in @pkts. */ int num_pkts; /* Interface that received @pkt. */ struct gatekeeper_if *iface; - /* ICMPv6 ping packets. */ + /* ICMPv6 packets. */ struct rte_mbuf *pkts[0]; }; @@ -131,12 +131,10 @@ struct lls_request { struct lls_put_req put; /* If @ty is LLS_REQ_ARP, use @arp. */ struct lls_arp_req arp; - /* If @ty is LLS_REQ_ND, use @nd. */ - struct lls_nd_req nd; - /* If @ty is LLS_REQ_PING, use @ping. */ - struct lls_ping_req ping; - /* If @ty is LLS_REQ_PING6, use @ping6. */ - struct lls_ping6_req ping6; + /* If @ty is LLS_REQ_ICMP, use @icmp. */ + struct lls_icmp_req icmp; + /* If @ty is LLS_REQ_ICMP6, use @icmp6. */ + struct lls_icmp6_req icmp6; } u; }; diff --git a/lls/main.c b/lls/main.c index 0c49d5eaa..0ba2a703e 100644 --- a/lls/main.c +++ b/lls/main.c @@ -50,14 +50,6 @@ * link partner does not have LACP configured). */ -/* The IPv6 all nodes multicast address. */ -static const struct in6_addr ip6_allnodes_mc_addr = { - .s6_addr = { - 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - } -}; - int lls_logtype; static struct lls_config lls_conf = { @@ -213,24 +205,24 @@ submit_arp(struct rte_mbuf **pkts, unsigned int num_pkts, } } -#define ND_REQ_SIZE(num_pkts) (offsetof(struct lls_request, end_of_header) + \ - sizeof(struct lls_nd_req) + sizeof(struct rte_mbuf *) * num_pkts) +#define ICMP_REQ_SIZE(num_pkts) (offsetof(struct lls_request, end_of_header) + \ + sizeof(struct lls_icmp_req) + sizeof(struct rte_mbuf *) * num_pkts) static int -submit_nd_neigh(struct rte_mbuf **pkts, unsigned int num_pkts, +submit_icmp(struct rte_mbuf **pkts, unsigned int num_pkts, struct gatekeeper_if *iface) { - struct lls_nd_req *nd_req; + struct lls_icmp_req *icmp_req; int ret; RTE_VERIFY(num_pkts <= lls_conf.mailbox_max_pkt_sub); - nd_req = alloca(ND_REQ_SIZE(num_pkts)); - nd_req->num_pkts = num_pkts; - nd_req->iface = iface; - rte_memcpy(nd_req->pkts, pkts, sizeof(*nd_req->pkts) * num_pkts); + icmp_req = alloca(ICMP_REQ_SIZE(num_pkts)); + icmp_req->num_pkts = num_pkts; + icmp_req->iface = iface; + rte_memcpy(icmp_req->pkts, pkts, sizeof(*icmp_req->pkts) * num_pkts); - ret = lls_req(LLS_REQ_ND, nd_req); + ret = lls_req(LLS_REQ_ICMP, icmp_req); if (unlikely(ret < 0)) { unsigned int i; for (i = 0; i < num_pkts; i++) @@ -242,188 +234,17 @@ submit_nd_neigh(struct rte_mbuf **pkts, unsigned int num_pkts, /* * Match the packet if it fails to be classifed by ACL rules. - * If it's an ND Neighbor packet, then submit it to the LLS block. * * Return values: 0 for successful match, and -ENOENT for no matching. */ static int -match_nd_neigh(struct rte_mbuf *pkt, struct gatekeeper_if *iface) -{ - /* - * The ND header offset in terms of the - * beginning of the IPv6 header. - */ - int nd_offset; - uint8_t nexthdr; - const uint16_t BE_ETHER_TYPE_IPv6 = - rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6); - struct rte_ether_hdr *eth_hdr = - rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); - struct rte_ipv6_hdr *ip6hdr; - struct icmpv6_hdr *nd_hdr; - uint16_t ether_type_be = pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip6hdr); - size_t l2_len = pkt_in_l2_hdr_len(pkt); - - if (unlikely(ether_type_be != BE_ETHER_TYPE_IPv6)) - return -ENOENT; - - if (pkt->data_len < ND_NEIGH_PKT_MIN_LEN(l2_len)) - return -ENOENT; - - if ((memcmp(ip6hdr->dst_addr, &iface->ip6_addr, - sizeof(iface->ip6_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, &iface->ll_ip6_addr, - sizeof(iface->ll_ip6_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, &iface->ip6_mc_addr, - sizeof(iface->ip6_mc_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, - &iface->ll_ip6_mc_addr, - sizeof(iface->ll_ip6_mc_addr)) != 0)) - return -ENOENT; - - if (rte_ipv6_frag_get_ipv6_fragment_header(ip6hdr) != NULL) { - LLS_LOG(WARNING, - "Received fragmented ND packets destined to this server at %s\n", - __func__); - return -ENOENT; - } - - nd_offset = ipv6_skip_exthdr(ip6hdr, pkt->data_len - l2_len, - &nexthdr); - if (nd_offset < 0 || nexthdr != IPPROTO_ICMPV6) - return -ENOENT; - - if (pkt->data_len < (ND_NEIGH_PKT_MIN_LEN(l2_len) + - nd_offset - sizeof(*ip6hdr))) - return -ENOENT; - - nd_hdr = (struct icmpv6_hdr *)((uint8_t *)ip6hdr + nd_offset); - if (nd_hdr->type != ND_NEIGHBOR_SOLICITATION && - nd_hdr->type != ND_NEIGHBOR_ADVERTISEMENT) - return -ENOENT; - - return 0; -} - -static int -drop_nd_router(struct rte_mbuf **pkts, unsigned int num_pkts, - __attribute__((unused)) struct gatekeeper_if *iface) -{ - unsigned int i; - for (i = 0; i < num_pkts; i++) - rte_pktmbuf_free(pkts[i]); - return 0; -} - -/* - * Match the packet if it fails to be classifed by ACL rules. - * If it's a router solicitation or advertisement packet, then drop it. - * - * Return values: 0 for successful match, and -ENOENT for no matching. - */ -static int -match_nd_router(struct rte_mbuf *pkt, struct gatekeeper_if *iface) -{ - /* - * The ND header offset in terms of the - * beginning of the IPv6 header. - */ - int nd_offset; - uint8_t nexthdr; - const uint16_t BE_ETHER_TYPE_IPv6 = - rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6); - struct rte_ether_hdr *eth_hdr = - rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); - struct rte_ipv6_hdr *ip6hdr; - struct icmpv6_hdr *nd_hdr; - uint16_t ether_type_be = pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip6hdr); - size_t l2_len = pkt_in_l2_hdr_len(pkt); - - if (unlikely(ether_type_be != BE_ETHER_TYPE_IPv6)) - return -ENOENT; - - if (pkt->data_len < ND_NEIGH_PKT_MIN_LEN(l2_len)) - return -ENOENT; - - if ((memcmp(ip6hdr->dst_addr, &ip6_allnodes_mc_addr, - sizeof(ip6_allnodes_mc_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, &iface->ip6_addr, - sizeof(iface->ip6_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, &iface->ll_ip6_addr, - sizeof(iface->ll_ip6_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, &iface->ip6_mc_addr, - sizeof(iface->ip6_mc_addr)) != 0) && - (memcmp(ip6hdr->dst_addr, - &iface->ll_ip6_mc_addr, - sizeof(iface->ll_ip6_mc_addr)) != 0)) - return -ENOENT; - - if (rte_ipv6_frag_get_ipv6_fragment_header(ip6hdr) != NULL) { - LLS_LOG(WARNING, - "Received fragmented ND packets destined to this server at %s\n", - __func__); - return -ENOENT; - } - - nd_offset = ipv6_skip_exthdr(ip6hdr, pkt->data_len - l2_len, - &nexthdr); - if (nd_offset < 0 || nexthdr != IPPROTO_ICMPV6) - return -ENOENT; - - if (pkt->data_len < (ND_NEIGH_PKT_MIN_LEN(l2_len) + - nd_offset - sizeof(*ip6hdr))) - return -ENOENT; - - nd_hdr = (struct icmpv6_hdr *)((uint8_t *)ip6hdr + nd_offset); - if (nd_hdr->type != ND_ROUTER_SOLICITATION && - nd_hdr->type != ND_ROUTER_ADVERTISEMENT) - return -ENOENT; - - return 0; -} - -#define PING_REQ_SIZE(num_pkts) (offsetof(struct lls_request, end_of_header) + \ - sizeof(struct lls_ping_req) + sizeof(struct rte_mbuf *) * num_pkts) - -static int -submit_ping(struct rte_mbuf **pkts, unsigned int num_pkts, - struct gatekeeper_if *iface) -{ - struct lls_ping_req *ping_req; - int ret; - - RTE_VERIFY(num_pkts <= lls_conf.mailbox_max_pkt_sub); - - ping_req = alloca(PING_REQ_SIZE(num_pkts)); - ping_req->num_pkts = num_pkts; - ping_req->iface = iface; - rte_memcpy(ping_req->pkts, pkts, sizeof(*ping_req->pkts) * num_pkts); - - ret = lls_req(LLS_REQ_PING, ping_req); - if (unlikely(ret < 0)) { - unsigned int i; - for (i = 0; i < num_pkts; i++) - rte_pktmbuf_free(pkts[i]); - return ret; - } - return 0; -} - -/* - * Match the packet if it fails to be classifed by ACL rules. - * If it's an IPv4 ping packet, then respond to the ICMPv4 ping. - * - * Return values: 0 for successful match, and -ENOENT for no matching. - */ -static int -match_ping(struct rte_mbuf *pkt, struct gatekeeper_if *iface) +match_icmp(struct rte_mbuf *pkt, struct gatekeeper_if *iface) { const uint16_t BE_ETHER_TYPE_IPv4 = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); struct rte_ipv4_hdr *ip4hdr; - struct rte_icmp_hdr *icmphdr; uint16_t ether_type_be = pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip4hdr); size_t l2_len = pkt_in_l2_hdr_len(pkt); @@ -445,37 +266,32 @@ match_ping(struct rte_mbuf *pkt, struct gatekeeper_if *iface) if (rte_ipv4_frag_pkt_is_fragmented(ip4hdr)) { LLS_LOG(WARNING, - "Received fragmented ping packets destined to this server at %s\n", + "Received fragmented ICMP packets destined to this server at %s\n", __func__); return -ENOENT; } - icmphdr = (struct rte_icmp_hdr *)ipv4_skip_exthdr(ip4hdr); - if (icmphdr->icmp_type != ICMP_ECHO_REQUEST_TYPE || - icmphdr->icmp_code != ICMP_ECHO_REQUEST_CODE) - return -ENOENT; - return 0; } -#define PING6_REQ_SIZE(num_pkts) (offsetof(struct lls_request, end_of_header) + \ - sizeof(struct lls_ping6_req) + sizeof(struct rte_mbuf *) * num_pkts) +#define ICMP6_REQ_SIZE(num_pkts) (offsetof(struct lls_request, end_of_header) + \ + sizeof(struct lls_icmp6_req) + sizeof(struct rte_mbuf *) * num_pkts) static int -submit_ping6(struct rte_mbuf **pkts, unsigned int num_pkts, +submit_icmp6(struct rte_mbuf **pkts, unsigned int num_pkts, struct gatekeeper_if *iface) { - struct lls_ping6_req *ping6_req; + struct lls_icmp6_req *icmp6_req; int ret; RTE_VERIFY(num_pkts <= lls_conf.mailbox_max_pkt_sub); - ping6_req = alloca(PING6_REQ_SIZE(num_pkts)); - ping6_req->num_pkts = num_pkts; - ping6_req->iface = iface; - rte_memcpy(ping6_req->pkts, pkts, sizeof(*ping6_req->pkts) * num_pkts); + icmp6_req = alloca(ICMP6_REQ_SIZE(num_pkts)); + icmp6_req->num_pkts = num_pkts; + icmp6_req->iface = iface; + rte_memcpy(icmp6_req->pkts, pkts, sizeof(*icmp6_req->pkts) * num_pkts); - ret = lls_req(LLS_REQ_PING6, ping6_req); + ret = lls_req(LLS_REQ_ICMP6, icmp6_req); if (unlikely(ret < 0)) { unsigned int i; for (i = 0; i < num_pkts; i++) @@ -487,15 +303,14 @@ submit_ping6(struct rte_mbuf **pkts, unsigned int num_pkts, /* * Match the packet if it fails to be classifed by ACL rules. - * If it's an IPv6 ping packet, then respond to the ICMPv6 ping. * * Return values: 0 for successful match, and -ENOENT for no matching. */ static int -match_ping6(struct rte_mbuf *pkt, struct gatekeeper_if *iface) +match_icmp6(struct rte_mbuf *pkt, struct gatekeeper_if *iface) { /* - * The icmpv6 header offset in terms of the + * The ICMPv6 header offset in terms of the * beginning of the IPv6 header. */ int icmpv6_offset; @@ -505,7 +320,6 @@ match_ping6(struct rte_mbuf *pkt, struct gatekeeper_if *iface) struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); struct rte_ipv6_hdr *ip6hdr; - struct icmpv6_hdr *icmp6_hdr; uint16_t ether_type_be = pkt_in_skip_l2(pkt, eth_hdr, (void **)&ip6hdr); size_t l2_len = pkt_in_l2_hdr_len(pkt); @@ -523,12 +337,14 @@ match_ping6(struct rte_mbuf *pkt, struct gatekeeper_if *iface) sizeof(iface->ip6_mc_addr)) != 0) && (memcmp(ip6hdr->dst_addr, &iface->ll_ip6_mc_addr, - sizeof(iface->ll_ip6_mc_addr)) != 0)) + sizeof(iface->ll_ip6_mc_addr)) != 0) && + (memcmp(ip6hdr->dst_addr, &ip6_allnodes_mc_addr, + sizeof(ip6_allnodes_mc_addr)) != 0)) return -ENOENT; if (rte_ipv6_frag_get_ipv6_fragment_header(ip6hdr) != NULL) { LLS_LOG(WARNING, - "Received fragmented ping6 packets destined to this server at %s\n", + "Received fragmented ICMPv6 packets destined to this server at %s\n", __func__); return -ENOENT; } @@ -542,11 +358,6 @@ match_ping6(struct rte_mbuf *pkt, struct gatekeeper_if *iface) icmpv6_offset - sizeof(*ip6hdr))) return -ENOENT; - icmp6_hdr = (struct icmpv6_hdr *)((uint8_t *)ip6hdr + icmpv6_offset); - if (icmp6_hdr->type != ICMPV6_ECHO_REQUEST_TYPE || - icmp6_hdr->code != ICMPV6_ECHO_REQUEST_CODE) - return -ENOENT; - return 0; } @@ -854,73 +665,7 @@ lls_proc(void *arg) } static void -fill_nd_rule(struct ipv6_acl_rule *rule, const struct in6_addr *addr, - int nd_type) -{ - const uint32_t *ptr32 = (const uint32_t *)addr; - int i; - - RTE_VERIFY(nd_type == ND_ROUTER_SOLICITATION || - nd_type == ND_ROUTER_ADVERTISEMENT || - nd_type == ND_NEIGHBOR_SOLICITATION || - nd_type == ND_NEIGHBOR_ADVERTISEMENT); - - rule->data.category_mask = 0x1; - rule->data.priority = 1; - /* Userdata is filled in in register_ipv6_acl(). */ - - rule->field[PROTO_FIELD_IPV6].value.u8 = IPPROTO_ICMPV6; - rule->field[PROTO_FIELD_IPV6].mask_range.u8 = 0xFF; - - for (i = DST1_FIELD_IPV6; i <= DST4_FIELD_IPV6; i++) { - rule->field[i].value.u32 = rte_be_to_cpu_32(*ptr32); - rule->field[i].mask_range.u32 = 32; - ptr32++; - } - - rule->field[TYPE_FIELD_ICMPV6].value.u32 = (nd_type << 24) & 0xFF000000; - rule->field[TYPE_FIELD_ICMPV6].mask_range.u32 = 0xFF000000; -} - -static int -register_nd_neigh_acl_rules(struct gatekeeper_if *iface) -{ - struct ipv6_acl_rule ipv6_rules[8]; - int ret; - - memset(&ipv6_rules, 0, sizeof(ipv6_rules)); - - fill_nd_rule(&ipv6_rules[0], &iface->ip6_addr, - ND_NEIGHBOR_SOLICITATION); - fill_nd_rule(&ipv6_rules[1], &iface->ll_ip6_addr, - ND_NEIGHBOR_SOLICITATION); - fill_nd_rule(&ipv6_rules[2], &iface->ip6_mc_addr, - ND_NEIGHBOR_SOLICITATION); - fill_nd_rule(&ipv6_rules[3], &iface->ll_ip6_mc_addr, - ND_NEIGHBOR_SOLICITATION); - - fill_nd_rule(&ipv6_rules[4], &iface->ip6_addr, - ND_NEIGHBOR_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[5], &iface->ll_ip6_addr, - ND_NEIGHBOR_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[6], &iface->ip6_mc_addr, - ND_NEIGHBOR_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[7], &iface->ll_ip6_mc_addr, - ND_NEIGHBOR_ADVERTISEMENT); - - ret = register_ipv6_acl(ipv6_rules, RTE_DIM(ipv6_rules), - submit_nd_neigh, match_nd_neigh, iface); - if (ret < 0) { - LLS_LOG(ERR, "Could not register ND IPv6 ACL on %s iface\n", - iface->name); - return ret; - } - - return 0; -} - -static void -fill_ping_rule(struct ipv4_acl_rule *rule, struct in_addr *addr) +fill_icmp_rule(struct ipv4_acl_rule *rule, struct in_addr *addr) { rule->data.category_mask = 0x1; rule->data.priority = 1; @@ -932,31 +677,22 @@ fill_ping_rule(struct ipv4_acl_rule *rule, struct in_addr *addr) rule->field[DST_FIELD_IPV4].value.u32 = rte_be_to_cpu_32(addr->s_addr); rule->field[DST_FIELD_IPV4].mask_range.u32 = 32; - - /* - * The reason to have 0xFFFF0000 is to test - * both type and code at the same time. - */ - rule->field[TYPE_FIELD_ICMP].value.u32 = - ((ICMP_ECHO_REQUEST_TYPE << 24) | - (ICMP_ECHO_REQUEST_CODE << 16)) & 0xFFFF0000; - rule->field[TYPE_FIELD_ICMP].mask_range.u32 = 0xFFFF0000; } static int -register_ping_acl_rules(struct gatekeeper_if *iface) +register_icmp_acl_rules(struct gatekeeper_if *iface) { struct ipv4_acl_rule ipv4_rules[1]; int ret; memset(ipv4_rules, 0, sizeof(ipv4_rules)); - fill_ping_rule(&ipv4_rules[0], &iface->ip4_addr); + fill_icmp_rule(&ipv4_rules[0], &iface->ip4_addr); ret = register_ipv4_acl(ipv4_rules, RTE_DIM(ipv4_rules), - submit_ping, match_ping, iface); + submit_icmp, match_icmp, iface); if (ret < 0) { - LLS_LOG(ERR, "Could not register ping IPv4 ACL on %s iface\n", + LLS_LOG(ERR, "Could not register ICMP ACL on %s iface\n", iface->name); return ret; } @@ -965,9 +701,9 @@ register_ping_acl_rules(struct gatekeeper_if *iface) } static void -fill_ping6_rule(struct ipv6_acl_rule *rule, struct in6_addr *addr) +fill_icmp6_rule(struct ipv6_acl_rule *rule, const struct in6_addr *addr) { - uint32_t *ptr32 = (uint32_t *)addr; + const uint32_t *ptr32 = (const uint32_t *)addr; int i; rule->data.category_mask = 0x1; @@ -982,79 +718,32 @@ fill_ping6_rule(struct ipv6_acl_rule *rule, struct in6_addr *addr) rule->field[i].mask_range.u32 = 32; ptr32++; } - - /* - * The reason to have 0xFFFF0000 is to test - * both type and code at the same time. - */ - rule->field[TYPE_FIELD_ICMPV6].value.u32 = - ((ICMPV6_ECHO_REQUEST_TYPE << 24) | - (ICMPV6_ECHO_REQUEST_CODE << 16)) & 0xFFFF0000; - rule->field[TYPE_FIELD_ICMPV6].mask_range.u32 = 0xFFFF0000; } static int -register_ping6_acl_rules(struct gatekeeper_if *iface) +register_icmp6_acl_rules(struct gatekeeper_if *iface) { - struct ipv6_acl_rule ipv6_rules[4]; + struct ipv6_acl_rule ipv6_rules[5]; int ret; memset(&ipv6_rules, 0, sizeof(ipv6_rules)); + /* All of the IPv6 addresses that a Gatekeeper interface supports. */ + fill_icmp6_rule(&ipv6_rules[0], &iface->ip6_addr); + fill_icmp6_rule(&ipv6_rules[1], &iface->ll_ip6_addr); + fill_icmp6_rule(&ipv6_rules[2], &iface->ip6_mc_addr); + fill_icmp6_rule(&ipv6_rules[3], &iface->ll_ip6_mc_addr); /* - * According to RFC 4443 section 4.1, the Destination Address of an - * ICMPv6 Echo Request message can be any legal IPv6 address. + * The all nodes multicast address is only used to ignore + * router solitication/advertisement messages so that they + * do not clutter the Gatekeeper log. */ - fill_ping6_rule(&ipv6_rules[0], &iface->ip6_addr); - fill_ping6_rule(&ipv6_rules[1], &iface->ll_ip6_addr); - fill_ping6_rule(&ipv6_rules[2], &iface->ip6_mc_addr); - fill_ping6_rule(&ipv6_rules[3], &iface->ll_ip6_mc_addr); + fill_icmp6_rule(&ipv6_rules[4], &ip6_allnodes_mc_addr); ret = register_ipv6_acl(ipv6_rules, RTE_DIM(ipv6_rules), - submit_ping6, match_ping6, iface); + submit_icmp6, match_icmp6, iface); if (ret < 0) { - LLS_LOG(ERR, "Could not register ping IPv6 ACL on %s iface\n", - iface->name); - return ret; - } - - return 0; -} - -static int -register_nd_router_acl_rules(struct gatekeeper_if *iface) -{ - struct ipv6_acl_rule ipv6_rules[10]; - int ret; - - memset(&ipv6_rules, 0, sizeof(ipv6_rules)); - - fill_nd_rule(&ipv6_rules[0], &iface->ip6_addr, - ND_ROUTER_SOLICITATION); - fill_nd_rule(&ipv6_rules[1], &iface->ll_ip6_addr, - ND_ROUTER_SOLICITATION); - fill_nd_rule(&ipv6_rules[2], &iface->ip6_mc_addr, - ND_ROUTER_SOLICITATION); - fill_nd_rule(&ipv6_rules[3], &iface->ll_ip6_mc_addr, - ND_ROUTER_SOLICITATION); - fill_nd_rule(&ipv6_rules[4], &ip6_allnodes_mc_addr, - ND_ROUTER_SOLICITATION); - - fill_nd_rule(&ipv6_rules[5], &iface->ip6_addr, - ND_ROUTER_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[6], &iface->ll_ip6_addr, - ND_ROUTER_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[7], &iface->ip6_mc_addr, - ND_ROUTER_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[8], &iface->ll_ip6_mc_addr, - ND_ROUTER_ADVERTISEMENT); - fill_nd_rule(&ipv6_rules[9], &ip6_allnodes_mc_addr, - ND_ROUTER_ADVERTISEMENT); - - ret = register_ipv6_acl(ipv6_rules, RTE_DIM(ipv6_rules), - drop_nd_router, match_nd_router, iface); - if (ret < 0) { - LLS_LOG(ERR, "Could not register ND Router Solicitation or Advertisement IPv6 ACL on %s iface\n", + LLS_LOG(ERR, "Could not register ICMPv6 ACL on %s iface\n", iface->name); return ret; } @@ -1150,9 +839,8 @@ lls_stage1(void *arg) struct lls_config *lls_conf = arg; int ele_size = RTE_MAX(sizeof(struct lls_request), RTE_MAX(ARP_REQ_SIZE(lls_conf->mailbox_max_pkt_sub), - RTE_MAX(ND_REQ_SIZE(lls_conf->mailbox_max_pkt_sub), - RTE_MAX(PING_REQ_SIZE(lls_conf->mailbox_max_pkt_sub), - PING6_REQ_SIZE(lls_conf->mailbox_max_pkt_sub))))); + RTE_MAX(ICMP_REQ_SIZE(lls_conf->mailbox_max_pkt_sub), + ICMP6_REQ_SIZE(lls_conf->mailbox_max_pkt_sub)))); int ret = assign_lls_queue_ids(lls_conf); if (ret < 0) return ret; @@ -1204,8 +892,8 @@ lls_stage2(void *arg) return -1; } - /* Receive ping packets using IPv4 ACL filters. */ - ret = register_ping_acl_rules(&net_conf->front); + /* Receive ICMP packets using IPv4 ACL filters. */ + ret = register_icmp_acl_rules(&net_conf->front); if (ret < 0) return ret; } @@ -1222,8 +910,8 @@ lls_stage2(void *arg) return -1; } - /* Receive ping packets using IPv4 ACL filters. */ - ret = register_ping_acl_rules(&net_conf->back); + /* Receive ICMP packets using IPv4 ACL filters. */ + ret = register_icmp_acl_rules(&net_conf->back); if (ret < 0) return ret; } @@ -1231,25 +919,13 @@ lls_stage2(void *arg) /* Receive ND packets using IPv6 ACL filters. */ if (lls_conf->nd_cache.iface_enabled(net_conf, &net_conf->front)) { - ret = register_nd_neigh_acl_rules(&net_conf->front); - if (ret < 0) - return ret; - ret = register_nd_router_acl_rules(&net_conf->front); - if (ret < 0) - return ret; - ret = register_ping6_acl_rules(&net_conf->front); + ret = register_icmp6_acl_rules(&net_conf->front); if (ret < 0) return ret; } if (lls_conf->nd_cache.iface_enabled(net_conf, &net_conf->back)) { - ret = register_nd_neigh_acl_rules(&net_conf->back); - if (ret < 0) - return ret; - ret = register_nd_router_acl_rules(&net_conf->back); - if (ret < 0) - return ret; - ret = register_ping6_acl_rules(&net_conf->back); + ret = register_icmp6_acl_rules(&net_conf->back); if (ret < 0) return ret; } diff --git a/lls/nd.c b/lls/nd.c index b4de718ec..013f73494 100644 --- a/lls/nd.c +++ b/lls/nd.c @@ -201,8 +201,8 @@ xmit_nd_req(struct gatekeeper_if *iface, const struct ipaddr *addr, /* Set-up ICMPv6 header. */ icmpv6_hdr = (struct icmpv6_hdr *)&ipv6_hdr[1]; - icmpv6_hdr->type = ND_NEIGHBOR_SOLICITATION; - icmpv6_hdr->code = 0; + icmpv6_hdr->type = ND_NEIGHBOR_SOLICITATION_TYPE; + icmpv6_hdr->code = ND_NEIGHBOR_SOLICITATION_CODE; icmpv6_hdr->cksum = 0; /* Calculated below. */ /* Set-up ND header with options. */ @@ -446,7 +446,8 @@ process_nd_neigh_solicitation(struct lls_config *lls_conf, struct rte_mbuf *buf, sizeof(ipv6_hdr->src_addr)); /* Set-up ICMPv6 header. */ - icmpv6_hdr->type = ND_NEIGHBOR_ADVERTISEMENT; + icmpv6_hdr->type = ND_NEIGHBOR_ADVERTISEMENT_TYPE; + icmpv6_hdr->code = ND_NEIGHBOR_ADVERTISEMENT_CODE; icmpv6_hdr->cksum = 0; /* Calculated below. */ /* Set up ND Advertisement header with target LL addr option. */ @@ -690,16 +691,21 @@ process_nd(struct lls_config *lls_conf, struct gatekeeper_if *iface, eth_hdr = rte_pktmbuf_mtod(buf, struct rte_ether_hdr *); switch (icmpv6_hdr->type) { - case ND_NEIGHBOR_SOLICITATION: + case ND_NEIGHBOR_SOLICITATION_TYPE: + if (icmpv6_hdr->code != ND_NEIGHBOR_SOLICITATION_CODE) + goto log; return process_nd_neigh_solicitation(lls_conf, buf, eth_hdr, ipv6_hdr, icmpv6_hdr, pkt_len, l2_len, icmpv6_len, iface, tx_queue); - case ND_NEIGHBOR_ADVERTISEMENT: + case ND_NEIGHBOR_ADVERTISEMENT_CODE: + if (icmpv6_hdr->code != ND_NEIGHBOR_ADVERTISEMENT_CODE) + goto log; return process_nd_neigh_advertisement(lls_conf, ipv6_hdr, icmpv6_hdr, icmpv6_len, iface); default: - LLS_LOG(NOTICE, "%s received an ICMPv6 packet that's not a Neighbor Solicitation or Neighbor Advertisement (%hhu)\n", - __func__, icmpv6_hdr->type); +log: + LLS_LOG(NOTICE, "%s received an ICMPv6 packet that's not a Neighbor Solicitation or Neighbor Advertisement (type=%hhu, code=%hhu)\n", + __func__, icmpv6_hdr->type, icmpv6_hdr->code); return -1; }