Skip to content

Commit 4854315

Browse files
committed
Added FDIR using general flow rules.
Added FDIR functionality that does not use flow in isolation mode. This is a part of the research work at RCSLab, University of Waterloo
1 parent 0e1e4ad commit 4854315

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

lib/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ FF_KNI=1
3636
endif
3737

3838
#FF_FLOW_ISOLATE=1
39+
#FF_FDIR=1
3940

4041
# NETGRAPH drivers ipfw
4142
#FF_NETGRAPH=1
@@ -84,6 +85,10 @@ endif
8485
HOST_CFLAGS+= ${DPDK_CFLAGS}
8586
HOST_CFLAGS+= ${CONF_CFLAGS}
8687

88+
ifdef FF_FDIR
89+
HOST_CFLAGS+= -DFF_FDIR
90+
endif
91+
8792
ifdef FF_FLOW_ISOLATE
8893
HOST_CFLAGS+= -DFF_FLOW_ISOLATE
8994
endif

lib/ff_dpdk_if.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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. */
844844
static int
845845
port_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
884887
static int
885888
port_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+
10491156
int
10501157
ff_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

Comments
 (0)