From 856b7f1995c12ba4df80127ba8e9e3f400571846 Mon Sep 17 00:00:00 2001 From: Alex Naslednikov Date: Tue, 9 Nov 2010 16:46:42 +0000 Subject: [PATCH] [IPOIB_NDIS6_CM] Initial commit for IPv6; Supports all the flows except DHCP git-svn-id: svn://openib.tc.cornell.edu/gen1@2984 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- trunk/inc/kernel/ip_packet.h | 80 +++++++- trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h | 1 + .../ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp | 177 +++++++++++++++--- 3 files changed, 225 insertions(+), 33 deletions(-) diff --git a/trunk/inc/kernel/ip_packet.h b/trunk/inc/kernel/ip_packet.h index 663729da..6c7ddf77 100644 --- a/trunk/inc/kernel/ip_packet.h +++ b/trunk/inc/kernel/ip_packet.h @@ -200,6 +200,7 @@ typedef struct _arp_pkt #define IP_PROT_UDP 17 #define IP_PROT_IGMP 2 #define IP_PROT_ICMP 1 +#define IP_PROT_ICMPV6 58 #include @@ -263,6 +264,72 @@ typedef struct _ip_hdr *********/ #include +#include +/****s* IB Network Drivers/ipv6_hdr_t +* NAME +* ipv6_hdr_t +* +* DESCRIPTION +* Defines the IPV6 header for IPV6 packets. +* +* SYNOPSIS +*/ +typedef struct _ipv6_hdr +{ + uint32_t ver_tc_fl; + uint16_t payload_length; + uint8_t next_header; + uint8_t hop_limit; + uint8_t src_addr[16]; + uint8_t dest_addr[16]; + +} PACK_SUFFIX ipv6_hdr_t; +/* +* FIELDS +* ver_tc_fl +* This field contains of 3 subfields: +* 1.Version (4 bits) +* The constant 6 (bit sequence 0110). +* 2.Traffic Class (8 bits) +* The bits of this field hold two values. The 6 most-significant bits are used +* for DSCP, which is used to classify packets. The remaining two bits +* are used for ECN; priority values subdivide into ranges: traffic where +* the source provides congestion control and non-congestion control traffic. +* 3.Flow Label (20 bits) +* Originally created for giving real-time applications special service. +* Flow Label specifications and minimum requirements are described, +* and first uses of this field are emerging. +* +* +* payload_length; +* The size of the payload in octets, including any extension headers. +* The length is set to zero when a Hop-by-Hop extension header carries +* a Jumbo Payload option. +* +* next_header +* Specifies the type of the next header. This field usually specifies the +* transport layer protocol used by a packet's payload. When extension headers +* are present in the packet this field indicates which extension header follows. +* The values are shared with those used for the IPv4 protocol field, +* as both fields have the same function +* +* hop_limit +* Replaces the time to live field of IPv4. This value is decremented by +* one at each intermediate node the packet visits. When the counter reaches +* 0 the packet is discarded +* +* src_addr +* The IPv6 address of the sending node. +* +* dest_addr +* The IPv6 address of the destination node(s). +* +* +* SEE ALSO +* IB Network Drivers, eth_hdr_t, arp_pkt_t, tcp_hdr_t, udp_hdr_t +*********/ +#include + #include /****s* IB Network Drivers/tcp_hdr_t @@ -432,8 +499,11 @@ typedef struct _igmp_v2_hdr *********/ #include -#define DHCP_PORT_SERVER CL_HTON16(67) -#define DHCP_PORT_CLIENT CL_HTON16(68) +#define DHCP_PORT_SERVER CL_HTON16(67) +#define DHCP_PORT_CLIENT CL_HTON16(68) +#define DHCP_IPV6_PORT_SERVER_OR_AGENT CL_HTON16(547) +#define DHCP_IPV6_PORT_CLIENT CL_HTON16(546) + #define DHCP_PORT_PROXY_SERVER CL_HTON16(4011) #define DHCP_REQUEST 1 @@ -534,7 +604,11 @@ typedef struct _udp_pkt typedef struct _ip_pkt { - ip_hdr_t hdr; + union + { + ip_hdr_t hdr; + ipv6_hdr_t hdr_ipv6; + } PACK_SUFFIX ; union _ip_payload { tcp_hdr_t tcp; diff --git a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h index d45f9054..0cb3d5a0 100644 --- a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_debug.h @@ -205,6 +205,7 @@ enum ipoib_perf_counters BuildSendDesc, SendMgrFilter, FilterIp, + FilterIpV6, QueryIp, SendTcp, FilterUdp, diff --git a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp index 7a242ae5..3c6d22d4 100644 --- a/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp +++ b/trunk/ulp/ipoib_NDIS6_CM/kernel/ipoib_port.cpp @@ -349,9 +349,10 @@ __send_mgr_filter_igmp_v2( static NDIS_STATUS __send_mgr_filter_udp( - IN const ip_hdr_t* const p_ip_hdr, + IN const void* const p_ip_hdr, IN MDL* p_mdl, IN size_t buf_len, + IN uint8_t prot, IN OUT ipoib_send_NB_SG* const s_buf); static NDIS_STATUS @@ -609,11 +610,17 @@ inline void ipoib_port_deref(ipoib_port_t * p_port, int type) /* function returns pointer to payload that is going after IP header. * asssuming that payload and IP header are in the same buffer */ -static void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr) +static inline void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr) { return (void*)((uint8_t*)p_ip_hdr + IP_HEADER_LENGTH(p_ip_hdr)); } +static inline void* GetIpv6PayloadPtr(const ipv6_hdr_t* const p_ipv6_hdr) +{ + return (void*)((uint8_t*)p_ipv6_hdr + p_ipv6_hdr->payload_length); +} + + /****************************************************************************** * * Implementation @@ -2522,6 +2529,67 @@ __recv_mgr_filter( switch( p_ipoib->hdr.type ) { + case ETH_PROT_TYPE_IPV6: + if( len < (sizeof(ipoib_hdr_t) + sizeof(ipv6_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received IP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + if( p_ipoib->type.ip.hdr_ipv6.next_header != IP_PROT_UDP ) + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvTcp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvTcp ); + break; + } + //ASSERT( p_ipoib->type.ip.hdr_ipv6.payload_length == sizeof(ipv6_hdr_t) ); + + /* First packet of a UDP transfer. */ + if( len < + (sizeof(ipoib_hdr_t) + sizeof(ipv6_hdr_t) + sizeof(udp_hdr_t)) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received UDP packet < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + /* Check if DHCP conversion is required. */ + if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_IPV6_PORT_SERVER_OR_AGENT&& + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_IPV6_PORT_CLIENT) || + (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_IPV6_PORT_CLIENT && + p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_IPV6_PORT_SERVER_OR_AGENT)) + { + //TODO should be DHCP IPv6 + if( len < (sizeof(ipoib_hdr_t) + sizeof(ipv6_hdr_t) + + sizeof(udp_hdr_t) /*+ DHCP_MIN_SIZE*/) ) + { + IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, + ("Received DHCP < min size\n") ); + status = IB_INVALID_SETTING; + break; + } + + /* UDP packet with BOOTP ports in src/dst port numbers. */ + cl_perf_start( RecvDhcp ); + //TODO implement this function + //status = __recv_dhcp_ipv6( p_port, p_ipoib, p_eth, p_src, p_dst ); + status = IB_INVALID_SETTING; + cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp ); + } + else + { + /* Unfiltered. Setup the ethernet header and report. */ + cl_perf_start( RecvUdp ); + status = __recv_gen( p_ipoib, p_eth, p_src, p_dst ); + cl_perf_stop( &p_port->p_adapter->perf, RecvUdp ); + } + break; + case ETH_PROT_TYPE_IP: if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) ) { @@ -3479,6 +3547,11 @@ __send_mgr_filter( switch( p_eth_hdr->type ) { + case ETH_PROT_TYPE_IPV6: + cl_perf_start( FilterIpV6 ); + status = __send_mgr_filter_ip( p_eth_hdr, p_mdl, buf_len, s_buf ); + cl_perf_stop( &p_port->p_adapter->perf, FilterIpV6 ); + break; case ETH_PROT_TYPE_IP: cl_perf_start( FilterIp ); status = __send_mgr_filter_ip( p_eth_hdr, p_mdl, buf_len, s_buf ); @@ -4294,10 +4367,12 @@ __send_mgr_filter_ip( IN ipoib_send_NB_SG *s_buf ) { NDIS_STATUS status; - ip_hdr_t *p_ip_hdr; + PVOID p_ip_hdr; uint32_t ip_packet_len; size_t iph_size_in_bytes; size_t iph_options_size; + uint8_t prot; + size_t hdr_size; PERF_DECLARE( QueryIp ); PERF_DECLARE( SendTcp ); @@ -4328,10 +4403,20 @@ __send_mgr_filter_ip( } else { - p_ip_hdr = (ip_hdr_t*)(p_eth_hdr + 1); + p_ip_hdr = (PVOID) (p_eth_hdr + 1); } - - if( buf_len < sizeof(ip_hdr_t) ) + + if ( p_eth_hdr->type == ETH_PROT_TYPE_IPV6 ) + { + prot = ((ipv6_hdr_t *) p_ip_hdr)->next_header; + hdr_size = sizeof(ipv6_hdr_t); + } + else //IPv4 + { + prot = ((ip_hdr_t *) p_ip_hdr)->prot; + hdr_size = sizeof(ip_hdr_t); + } + if( buf_len < hdr_size ) { /* This buffer is done for. Get the next buffer. */ IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR, @@ -4339,12 +4424,12 @@ __send_mgr_filter_ip( return NDIS_STATUS_BUFFER_TOO_SHORT; } - switch( p_ip_hdr->prot ) + switch( prot ) { case IP_PROT_UDP: cl_perf_start( FilterUdp ); status = __send_mgr_filter_udp( p_ip_hdr, p_mdl, - (buf_len - sizeof(ip_hdr_t)), s_buf ); + (buf_len - hdr_size), prot, s_buf ); cl_perf_stop( &p_port->p_adapter->perf, FilterUdp ); if( status == NDIS_STATUS_PENDING ) { /* not DHCP packet, keep going */ @@ -4366,7 +4451,7 @@ __send_mgr_filter_ip( 2. ip options So to get the IGMP packet we need to skip the ip options NDIS_BUFFER */ - iph_size_in_bytes = (p_ip_hdr->ver_hl & 0xf) * 4; + iph_size_in_bytes = (((ip_hdr_t*)p_ip_hdr)->ver_hl & 0xf) * 4; iph_options_size = iph_size_in_bytes - buf_len; buf_len -= sizeof(ip_hdr_t);//without ipheader @@ -4376,7 +4461,7 @@ __send_mgr_filter_ip( We anyway pass it to __send_mgr_filter_igmp_v2(). */ status = __send_mgr_filter_igmp_v2( s_buf->p_port, - p_ip_hdr, + (ip_hdr_t*) p_ip_hdr, iph_options_size, p_mdl, buf_len ); @@ -4384,6 +4469,7 @@ __send_mgr_filter_ip( return status; case IP_PROT_ICMP: + case IP_PROT_ICMPV6: p_desc->send_dir = SEND_UD_QP; default: break; @@ -4400,7 +4486,7 @@ __send_mgr_filter_ip( } if( p_desc->send_dir == SEND_UD_QP ) { - ip_packet_len = cl_ntoh16( p_ip_hdr->length ); + ip_packet_len = cl_ntoh16( ((ip_hdr_t*)p_ip_hdr)->length ); //TODO add IPv6 support for CM flow if( ip_packet_len > s_buf->p_port->p_adapter->params.payload_mtu ) { //TODO: NDIS60 @@ -4565,10 +4651,11 @@ __send_mgr_filter_igmp_v2( static NDIS_STATUS __send_mgr_filter_udp( - IN const ip_hdr_t* const p_ip_hdr, - IN MDL* p_mdl, - IN size_t buf_len, - IN OUT ipoib_send_NB_SG* s_buf ) + IN const void* const p_ip_hdr, + IN MDL* p_mdl, + IN size_t buf_len, + IN uint8_t prot, + IN OUT ipoib_send_NB_SG* s_buf ) { NDIS_STATUS status; udp_hdr_t *p_udp_hdr; @@ -4598,17 +4685,25 @@ __send_mgr_filter_udp( } else { - p_udp_hdr = (udp_hdr_t*)GetIpPayloadPtr(p_ip_hdr); + if ( prot == ETH_PROT_TYPE_IPV6 ) + { + p_udp_hdr = (udp_hdr_t*)GetIpv6PayloadPtr((ipv6_hdr_t*)p_ip_hdr); + } + else //IPv4 + { + p_udp_hdr = (udp_hdr_t*)GetIpPayloadPtr((ip_hdr_t*)p_ip_hdr); + if (((ip_hdr_t*)p_ip_hdr)->offset > 0) { + /* This is a fragmented part of UDP packet + * Only first packet will contain UDP header in such case + * So, return if offset > 0 + */ + return NDIS_STATUS_PENDING; + } + } } /* Get the UDP header and check the destination port numbers. */ - if (p_ip_hdr->offset > 0) { - /* This is a fragmented part of UDP packet - * Only first packet will contain UDP header in such case - * So, return if offset > 0 - */ - return NDIS_STATUS_PENDING; - } + if( buf_len < sizeof(udp_hdr_t) ) { @@ -4617,13 +4712,26 @@ __send_mgr_filter_udp( return NDIS_STATUS_BUFFER_TOO_SHORT; } - if( (p_udp_hdr->src_port != DHCP_PORT_CLIENT || - p_udp_hdr->dst_port != DHCP_PORT_SERVER) && - (p_udp_hdr->src_port != DHCP_PORT_SERVER || - p_udp_hdr->dst_port != DHCP_PORT_CLIENT) ) + if ( prot == ETH_PROT_TYPE_IPV6 ) { + if( (p_udp_hdr->src_port != DHCP_PORT_CLIENT || + p_udp_hdr->dst_port != DHCP_PORT_SERVER) && + (p_udp_hdr->src_port != DHCP_PORT_SERVER || + p_udp_hdr->dst_port != DHCP_PORT_CLIENT) ) + { + /* Not a DHCP packet. */ + return NDIS_STATUS_PENDING; + } + } + else //IPv4 { - /* Not a DHCP packet. */ - return NDIS_STATUS_PENDING; + if( (p_udp_hdr->src_port != DHCP_IPV6_PORT_CLIENT|| + p_udp_hdr->dst_port != DHCP_IPV6_PORT_SERVER_OR_AGENT) && + (p_udp_hdr->src_port != DHCP_IPV6_PORT_SERVER_OR_AGENT || + p_udp_hdr->dst_port != DHCP_IPV6_PORT_CLIENT) ) + { + /* Not a DHCP packet. */ + return NDIS_STATUS_PENDING; + } } buf_len -= sizeof(udp_hdr_t); @@ -4638,7 +4746,16 @@ __send_mgr_filter_udp( return NDIS_STATUS_RESOURCES; } /* Copy the IP and UDP headers. */ - cl_memcpy( &s_buf->p_send_buf->ip.hdr, p_ip_hdr , sizeof(ip_hdr_t) ); + //TODO: in this case we limited IP size to 20, but it can be bigger, according to GetIpPayloadPtr + if ( prot == ETH_PROT_TYPE_IPV6 ) + { + cl_memcpy( &s_buf->p_send_buf->ip.hdr_ipv6, p_ip_hdr , sizeof(ipv6_hdr_t) ); + } + else + { + cl_memcpy( &s_buf->p_send_buf->ip.hdr, p_ip_hdr , sizeof(ip_hdr_t) ); + } + cl_memcpy( &s_buf->p_send_buf->ip.prot.udp.hdr, p_udp_hdr, sizeof(udp_hdr_t) ); -- 2.41.0