@@ -132,6 +132,17 @@ static dispatch_func_context_t packet_dispatcher_with_context;
132132
133133static uint16_t rss_reta_size [RTE_MAX_ETHPORTS ];
134134
135+ /* 0.3: per-port rte_thash ctx for dynamic sport reverse-calc.
136+ * Built once at init; -1 means disabled (fall back to soft scan). */
137+ static struct rte_thash_ctx * rss_thash_ctx [RTE_MAX_ETHPORTS ];
138+ static struct rte_thash_subtuple_helper * rss_thash_sport_h [RTE_MAX_ETHPORTS ];
139+ static int rss_thash_ready [RTE_MAX_ETHPORTS ];
140+ /* IPv4 tuple: saddr(4)|daddr(4)|sport(2)|dport(2); sport at byte 8 = bit 64. */
141+ #define FF_RSS_THASH_V4_TUPLE_LEN 12
142+ #define FF_RSS_THASH_V4_SPORT_OFF 64
143+ #define FF_RSS_THASH_SPORT_HELPER_LEN 16
144+ #define FF_RSS_THASH_ADJUST_ATTEMPTS 16
145+
135146#define BOND_DRIVER_NAME "net_bonding"
136147
137148static inline int send_single_packet (struct rte_mbuf * m , uint8_t port );
@@ -1433,6 +1444,7 @@ ff_dpdk_init(int argc, char **argv)
14331444 } else {
14341445 ff_log (FF_LOG_INFO , FF_LOGTYPE_FSTACK_LIB , "ff_rss_tbl_init successed\n" );
14351446 }
1447+ ff_rss_thash_ctx_init ();
14361448 }
14371449
14381450 init_clock ();
@@ -2885,6 +2897,145 @@ ff_rss_check(void *softc, uint32_t saddr, uint32_t daddr,
28852897 return ((hash & (reta_size - 1 )) % nb_queues ) == queueid ;
28862898}
28872899
2900+ static int
2901+ ff_rss_reta_log2 (uint16_t reta_size )
2902+ {
2903+ int log2 = 0 ;
2904+
2905+ while ((reta_size >>= 1 ) != 0 )
2906+ log2 ++ ;
2907+
2908+ return log2 ;
2909+ }
2910+
2911+ /*
2912+ * 0.3: build per-port thash ctx once at init so the dynamic path can
2913+ * reverse-calc a source port via rte_thash_adjust_tuple. Any failure marks
2914+ * the port unready and the dynamic path falls back to soft scan.
2915+ */
2916+ int
2917+ ff_rss_thash_ctx_init (void )
2918+ {
2919+ uint16_t port_id ;
2920+
2921+ if (rsskey == NULL || rsskey_len == 0 )
2922+ return -1 ;
2923+
2924+ for (port_id = 0 ; port_id < RTE_MAX_ETHPORTS ; port_id ++ ) {
2925+ char name [64 ];
2926+ uint16_t reta_size = rss_reta_size [port_id ];
2927+ uint32_t reta_log2 ;
2928+ struct rte_thash_ctx * ctx ;
2929+
2930+ rss_thash_ready [port_id ] = 0 ;
2931+
2932+ if (reta_size < 2 )
2933+ continue ;
2934+
2935+ reta_log2 = ff_rss_reta_log2 (reta_size );
2936+
2937+ snprintf (name , sizeof (name ), "ff_rss_thash_%u" , port_id );
2938+ ctx = rte_thash_init_ctx (name , rsskey_len , reta_log2 , rsskey , 0 );
2939+ if (ctx == NULL ) {
2940+ ff_log (FF_LOG_WARNING , FF_LOGTYPE_FSTACK_LIB ,
2941+ "rte_thash_init_ctx failed for port %u, dynamic rss path falls back to soft scan\n" ,
2942+ port_id );
2943+ continue ;
2944+ }
2945+
2946+ if (rte_thash_add_helper (ctx , "sport" ,
2947+ FF_RSS_THASH_SPORT_HELPER_LEN ,
2948+ FF_RSS_THASH_V4_SPORT_OFF ) != 0 ) {
2949+ ff_log (FF_LOG_WARNING , FF_LOGTYPE_FSTACK_LIB ,
2950+ "rte_thash_add_helper failed for port %u\n" , port_id );
2951+ rte_thash_free_ctx (ctx );
2952+ continue ;
2953+ }
2954+
2955+ rss_thash_sport_h [port_id ] = rte_thash_get_helper (ctx , "sport" );
2956+ if (rss_thash_sport_h [port_id ] == NULL ) {
2957+ rte_thash_free_ctx (ctx );
2958+ continue ;
2959+ }
2960+
2961+ rss_thash_ctx [port_id ] = ctx ;
2962+ rss_thash_ready [port_id ] = 1 ;
2963+ }
2964+
2965+ return 0 ;
2966+ }
2967+
2968+ /*
2969+ * 0.3: reverse-calc a host-order source port whose RSS hash lands on the
2970+ * caller's local queue. tuple layout mirrors ff_rss_check's hash input
2971+ * (saddr|daddr|sport|dport, host byte order). The result is always re-verified
2972+ * by ff_rss_check (zero tolerance for wrong queue); on any failure returns <0
2973+ * and the caller must fall back to the soft per-port scan.
2974+ */
2975+ int
2976+ ff_rss_adjust_sport (void * softc , uint32_t saddr , uint32_t daddr ,
2977+ uint16_t dport , uint16_t * out_sport )
2978+ {
2979+ struct lcore_conf * qconf = & lcore_conf ;
2980+ struct ff_dpdk_if_context * ctx = ff_veth_softc_to_hostc (softc );
2981+ uint16_t port_id , nb_queues , reta_size , queueid ;
2982+ uint32_t desired ;
2983+ uint8_t tuple [FF_RSS_THASH_V4_TUPLE_LEN ];
2984+ uint16_t sport ;
2985+ int tries ;
2986+
2987+ if (softc == NULL || out_sport == NULL )
2988+ return -1 ;
2989+
2990+ port_id = ctx -> port_id ;
2991+ if (!rss_thash_ready [port_id ] || rss_thash_ctx [port_id ] == NULL )
2992+ return -1 ;
2993+
2994+ nb_queues = qconf -> nb_queue_list [port_id ];
2995+ if (nb_queues <= 1 )
2996+ return -1 ;
2997+
2998+ reta_size = rss_reta_size [port_id ];
2999+ queueid = qconf -> tx_queue_id [port_id ];
3000+
3001+ /*
3002+ * desired_value picked from D(q) = { v in [0, reta_size) | v % Q == q }
3003+ * so (hash & (reta_size-1)) % nb_queues == queueid holds. Rotate the
3004+ * starting candidate to spread reta entries.
3005+ */
3006+ desired = queueid + (arc4random () % ((reta_size + nb_queues - 1 ) / nb_queues )) * nb_queues ;
3007+ if (desired >= reta_size )
3008+ desired = queueid ;
3009+
3010+ sport = 0 ;
3011+ for (tries = 0 ; tries < (int )((reta_size + nb_queues - 1 ) / nb_queues ); tries ++ ) {
3012+ if (desired >= reta_size )
3013+ desired = queueid ;
3014+
3015+ memset (tuple , 0 , sizeof (tuple ));
3016+ bcopy (& saddr , & tuple [0 ], sizeof (saddr ));
3017+ bcopy (& daddr , & tuple [4 ], sizeof (daddr ));
3018+ bcopy (& sport , & tuple [8 ], sizeof (sport ));
3019+ bcopy (& dport , & tuple [10 ], sizeof (dport ));
3020+
3021+ if (rte_thash_adjust_tuple (rss_thash_ctx [port_id ],
3022+ rss_thash_sport_h [port_id ], tuple , sizeof (tuple ),
3023+ desired & (reta_size - 1 ), FF_RSS_THASH_ADJUST_ATTEMPTS ,
3024+ NULL , NULL ) == 0 ) {
3025+ bcopy (& tuple [8 ], & sport , sizeof (sport ));
3026+ /* zero tolerance: confirm with the same soft hash. */
3027+ if (ff_rss_check (softc , saddr , daddr , sport , dport )) {
3028+ * out_sport = sport ;
3029+ return 0 ;
3030+ }
3031+ }
3032+
3033+ desired += nb_queues ;
3034+ }
3035+
3036+ return -1 ;
3037+ }
3038+
28883039void
28893040ff_regist_packet_dispatcher (dispatch_func_t func )
28903041{
0 commit comments