@@ -839,7 +839,7 @@ init_clock(void)
839839 return 0 ;
840840}
841841
842- #ifdef FF_FLOW_ISOLATE
842+ #if defined( FF_FLOW_ISOLATE ) || defined( FF_FDIR )
843843/** Print a message out of a flow error. */
844844static int
845845port_flow_complain (struct rte_flow_error * error )
@@ -880,7 +880,10 @@ port_flow_complain(struct rte_flow_error *error)
880880 rte_strerror (err ));
881881 return - err ;
882882}
883+ #endif
884+
883885
886+ #ifdef FF_FLOW_ISOLATE
884887static int
885888port_flow_isolate (uint16_t port_id , int set )
886889{
@@ -1046,6 +1049,110 @@ init_flow(uint16_t port_id, uint16_t tcp_port) {
10461049
10471050#endif
10481051
1052+ #ifdef FF_FDIR
1053+ /*
1054+ * Flow director allows the traffic to specific port to be processed on the
1055+ * specific queue. Unlike FF_FLOW_ISOLATE, the FF_FDIR implementation uses
1056+ * general flow rule so that most FDIR supported NIC will support. The best
1057+ * using case of FDIR is (but not limited to), using multiple processes to
1058+ * listen on different ports.
1059+ *
1060+ * This function can be called either in FSTACK or in end-application.
1061+ *
1062+ * Example:
1063+ * Given 2 fstack instances A and B. Instance A listens on port 80, and
1064+ * instance B listens on port 81. We want to process the traffic to port 80
1065+ * on rx queue 0, and the traffic to port 81 on rx queue 1.
1066+ * // port 80 rx queue 0
1067+ * ret = fdir_add_tcp_flow(port_id, 0, FF_FLOW_INGRESS, 0, 80);
1068+ * // port 81 rx queue 1
1069+ * ret = fdir_add_tcp_flow(port_id, 1, FF_FLOW_INGRESS, 0, 81);
1070+ */
1071+ #define FF_FLOW_EGRESS 1
1072+ #define FF_FLOW_INGRESS 2
1073+ /**
1074+ * Create a flow rule that moves packets with matching src and dest tcp port
1075+ * to the target queue.
1076+ *
1077+ * This function uses general flow rules and doesn't rely on the flow_isolation
1078+ * that not all the FDIR capable NIC support.
1079+ *
1080+ * @param port_id
1081+ * The selected port.
1082+ * @param queue
1083+ * The target queue.
1084+ * @param dir
1085+ * The direction of the traffic.
1086+ * 1 for egress, 2 for ingress and sum(1+2) for both.
1087+ * @param tcp_sport
1088+ * The src tcp port to match.
1089+ * @param tcp_dport
1090+ * The dest tcp port to match.
1091+ *
1092+ */
1093+ static int
1094+ fdir_add_tcp_flow (uint16_t port_id , uint16_t queue , uint16_t dir ,
1095+ uint16_t tcp_sport , uint16_t tcp_dport )
1096+ {
1097+ struct rte_flow_attr attr ;
1098+ struct rte_flow_item flow_pattern [4 ];
1099+ struct rte_flow_action flow_action [2 ];
1100+ struct rte_flow * flow = NULL ;
1101+ struct rte_flow_action_queue flow_action_queue = { .index = queue };
1102+ struct rte_flow_item_tcp tcp_spec ;
1103+ struct rte_flow_item_tcp tcp_mask ;
1104+ struct rte_flow_error rfe ;
1105+ int res ;
1106+
1107+ memset (flow_pattern , 0 , sizeof (flow_pattern ));
1108+ memset (flow_action , 0 , sizeof (flow_action ));
1109+
1110+ /*
1111+ * set the rule attribute.
1112+ */
1113+ memset (& attr , 0 , sizeof (struct rte_flow_attr ));
1114+ attr .ingress = ((dir & FF_FLOW_INGRESS ) > 0 );
1115+ attr .egress = ((dir & FF_FLOW_EGRESS ) > 0 );
1116+
1117+ /*
1118+ * create the action sequence.
1119+ * one action only, move packet to queue
1120+ */
1121+ flow_action [0 ].type = RTE_FLOW_ACTION_TYPE_QUEUE ;
1122+ flow_action [0 ].conf = & flow_action_queue ;
1123+ flow_action [1 ].type = RTE_FLOW_ACTION_TYPE_END ;
1124+
1125+ flow_pattern [0 ].type = RTE_FLOW_ITEM_TYPE_ETH ;
1126+ flow_pattern [1 ].type = RTE_FLOW_ITEM_TYPE_IPV4 ;
1127+
1128+ /*
1129+ * set the third level of the pattern (TCP).
1130+ */
1131+ memset (& tcp_spec , 0 , sizeof (struct rte_flow_item_tcp ));
1132+ memset (& tcp_mask , 0 , sizeof (struct rte_flow_item_tcp ));
1133+ tcp_spec .hdr .src_port = htons (tcp_sport );
1134+ tcp_mask .hdr .src_port = (tcp_sport == 0 ? 0 : 0xffff );
1135+ tcp_spec .hdr .dst_port = htons (tcp_dport );
1136+ tcp_mask .hdr .dst_port = (tcp_dport == 0 ? 0 : 0xffff );
1137+ flow_pattern [2 ].type = RTE_FLOW_ITEM_TYPE_TCP ;
1138+ flow_pattern [2 ].spec = & tcp_spec ;
1139+ flow_pattern [2 ].mask = & tcp_mask ;
1140+
1141+ flow_pattern [3 ].type = RTE_FLOW_ITEM_TYPE_END ;
1142+
1143+ res = rte_flow_validate (port_id , & attr , flow_pattern , flow_action , & rfe );
1144+ if (res )
1145+ return (1 );
1146+
1147+ flow = rte_flow_create (port_id , & attr , flow_pattern , flow_action , & rfe );
1148+ if (!flow )
1149+ return port_flow_complain (& rfe );
1150+
1151+ return (0 );
1152+ }
1153+
1154+ #endif
1155+
10491156int
10501157ff_dpdk_init (int argc , char * * argv )
10511158{
@@ -1114,6 +1221,16 @@ ff_dpdk_init(int argc, char **argv)
11141221 rte_exit (EXIT_FAILURE , "init_port_flow failed\n" );
11151222 }
11161223#endif
1224+
1225+ #ifdef FF_FDIR
1226+ /*
1227+ * Refer function header section for usage.
1228+ */
1229+ ret = fdir_add_tcp_flow (0 , 0 , FF_FLOW_INGRESS , 0 , 80 );
1230+ if (ret )
1231+ rte_exit (EXIT_FAILURE , "fdir_add_tcp_flow failed\n" );
1232+ #endif
1233+
11171234 return 0 ;
11181235}
11191236
0 commit comments