aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2013-03-19 06:18:11 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-19 17:15:04 -0400
commit77f65ebdca506870d99bfabe52bde222511022ec (patch)
tree8f5ba6c76d1b49b44128d08281cc0b6f3e62285c /net/packet
parentb0aa73bf081da6810dacd750b9f8186640e172db (diff)
packet: packet fanout rollover during socket overload
Changes: v3->v2: rebase (no other changes) passes selftest v2->v1: read f->num_members only once fix bug: test rollover mode + flag Minimize packet drop in a fanout group. If one socket is full, roll over packets to another from the group. Maintain flow affinity during normal load using an rxhash fanout policy, while dispersing unexpected traffic storms that hit a single cpu, such as spoofed-source DoS flows. Rollover breaks affinity for flows arriving at saturated sockets during those conditions. The patch adds a fanout policy ROLLOVER that rotates between sockets, filling each socket before moving to the next. It also adds a fanout flag ROLLOVER. If passed along with any other fanout policy, the primary policy is applied until the chosen socket is full. Then, rollover selects another socket, to delay packet drop until the entire system is saturated. Probing sockets is not free. Selecting the last used socket, as rollover does, is a greedy approach that maximizes chance of success, at the cost of extreme load imbalance. In practice, with sufficiently long queues to absorb bursts, sockets are drained in parallel and load balance looks uniform in `top`. To avoid contention, scales counters with number of sockets and accesses them lockfree. Values are bounds checked to ensure correctness. Tested using an application with 9 threads pinned to CPUs, one socket per thread and sufficient busywork per packet operation to limits each thread to handling 32 Kpps. When sent 500 Kpps single UDP stream packets, a FANOUT_CPU setup processes 32 Kpps in total without this patch, 270 Kpps with the patch. Tested with read() and with a packet ring (V1). Also, passes psock_fanout.c unit test added to selftests. Signed-off-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/af_packet.c109
-rw-r--r--net/packet/internal.h3
2 files changed, 88 insertions, 24 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1d6793dbfbae..bd0d14c97d41 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -181,6 +181,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
181 181
182struct packet_sock; 182struct packet_sock;
183static int tpacket_snd(struct packet_sock *po, struct msghdr *msg); 183static int tpacket_snd(struct packet_sock *po, struct msghdr *msg);
184static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
185 struct packet_type *pt, struct net_device *orig_dev);
184 186
185static void *packet_previous_frame(struct packet_sock *po, 187static void *packet_previous_frame(struct packet_sock *po,
186 struct packet_ring_buffer *rb, 188 struct packet_ring_buffer *rb,
@@ -973,11 +975,11 @@ static void *packet_current_rx_frame(struct packet_sock *po,
973 975
974static void *prb_lookup_block(struct packet_sock *po, 976static void *prb_lookup_block(struct packet_sock *po,
975 struct packet_ring_buffer *rb, 977 struct packet_ring_buffer *rb,
976 unsigned int previous, 978 unsigned int idx,
977 int status) 979 int status)
978{ 980{
979 struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb); 981 struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb);
980 struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, previous); 982 struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, idx);
981 983
982 if (status != BLOCK_STATUS(pbd)) 984 if (status != BLOCK_STATUS(pbd))
983 return NULL; 985 return NULL;
@@ -1041,6 +1043,29 @@ static void packet_increment_head(struct packet_ring_buffer *buff)
1041 buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; 1043 buff->head = buff->head != buff->frame_max ? buff->head+1 : 0;
1042} 1044}
1043 1045
1046static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
1047{
1048 struct sock *sk = &po->sk;
1049 bool has_room;
1050
1051 if (po->prot_hook.func != tpacket_rcv)
1052 return (atomic_read(&sk->sk_rmem_alloc) + skb->truesize)
1053 <= sk->sk_rcvbuf;
1054
1055 spin_lock(&sk->sk_receive_queue.lock);
1056 if (po->tp_version == TPACKET_V3)
1057 has_room = prb_lookup_block(po, &po->rx_ring,
1058 po->rx_ring.prb_bdqc.kactive_blk_num,
1059 TP_STATUS_KERNEL);
1060 else
1061 has_room = packet_lookup_frame(po, &po->rx_ring,
1062 po->rx_ring.head,
1063 TP_STATUS_KERNEL);
1064 spin_unlock(&sk->sk_receive_queue.lock);
1065
1066 return has_room;
1067}
1068
1044static void packet_sock_destruct(struct sock *sk) 1069static void packet_sock_destruct(struct sock *sk)
1045{ 1070{
1046 skb_queue_purge(&sk->sk_error_queue); 1071 skb_queue_purge(&sk->sk_error_queue);
@@ -1066,16 +1091,16 @@ static int fanout_rr_next(struct packet_fanout *f, unsigned int num)
1066 return x; 1091 return x;
1067} 1092}
1068 1093
1069static struct sock *fanout_demux_hash(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) 1094static unsigned int fanout_demux_hash(struct packet_fanout *f,
1095 struct sk_buff *skb,
1096 unsigned int num)
1070{ 1097{
1071 u32 idx, hash = skb->rxhash; 1098 return (((u64)skb->rxhash) * num) >> 32;
1072
1073 idx = ((u64)hash * num) >> 32;
1074
1075 return f->arr[idx];
1076} 1099}
1077 1100
1078static struct sock *fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) 1101static unsigned int fanout_demux_lb(struct packet_fanout *f,
1102 struct sk_buff *skb,
1103 unsigned int num)
1079{ 1104{
1080 int cur, old; 1105 int cur, old;
1081 1106
@@ -1083,14 +1108,40 @@ static struct sock *fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb
1083 while ((old = atomic_cmpxchg(&f->rr_cur, cur, 1108 while ((old = atomic_cmpxchg(&f->rr_cur, cur,
1084 fanout_rr_next(f, num))) != cur) 1109 fanout_rr_next(f, num))) != cur)
1085 cur = old; 1110 cur = old;
1086 return f->arr[cur]; 1111 return cur;
1112}
1113
1114static unsigned int fanout_demux_cpu(struct packet_fanout *f,
1115 struct sk_buff *skb,
1116 unsigned int num)
1117{
1118 return smp_processor_id() % num;
1087} 1119}
1088 1120
1089static struct sock *fanout_demux_cpu(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) 1121static unsigned int fanout_demux_rollover(struct packet_fanout *f,
1122 struct sk_buff *skb,
1123 unsigned int idx, unsigned int skip,
1124 unsigned int num)
1090{ 1125{
1091 unsigned int cpu = smp_processor_id(); 1126 unsigned int i, j;
1092 1127
1093 return f->arr[cpu % num]; 1128 i = j = min_t(int, f->next[idx], num - 1);
1129 do {
1130 if (i != skip && packet_rcv_has_room(pkt_sk(f->arr[i]), skb)) {
1131 if (i != j)
1132 f->next[idx] = i;
1133 return i;
1134 }
1135 if (++i == num)
1136 i = 0;
1137 } while (i != j);
1138
1139 return idx;
1140}
1141
1142static bool fanout_has_flag(struct packet_fanout *f, u16 flag)
1143{
1144 return f->flags & (flag >> 8);
1094} 1145}
1095 1146
1096static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, 1147static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
@@ -1099,7 +1150,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
1099 struct packet_fanout *f = pt->af_packet_priv; 1150 struct packet_fanout *f = pt->af_packet_priv;
1100 unsigned int num = f->num_members; 1151 unsigned int num = f->num_members;
1101 struct packet_sock *po; 1152 struct packet_sock *po;
1102 struct sock *sk; 1153 unsigned int idx;
1103 1154
1104 if (!net_eq(dev_net(dev), read_pnet(&f->net)) || 1155 if (!net_eq(dev_net(dev), read_pnet(&f->net)) ||
1105 !num) { 1156 !num) {
@@ -1110,23 +1161,31 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
1110 switch (f->type) { 1161 switch (f->type) {
1111 case PACKET_FANOUT_HASH: 1162 case PACKET_FANOUT_HASH:
1112 default: 1163 default:
1113 if (f->defrag) { 1164 if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
1114 skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET); 1165 skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
1115 if (!skb) 1166 if (!skb)
1116 return 0; 1167 return 0;
1117 } 1168 }
1118 skb_get_rxhash(skb); 1169 skb_get_rxhash(skb);
1119 sk = fanout_demux_hash(f, skb, num); 1170 idx = fanout_demux_hash(f, skb, num);
1120 break; 1171 break;
1121 case PACKET_FANOUT_LB: 1172 case PACKET_FANOUT_LB:
1122 sk = fanout_demux_lb(f, skb, num); 1173 idx = fanout_demux_lb(f, skb, num);
1123 break; 1174 break;
1124 case PACKET_FANOUT_CPU: 1175 case PACKET_FANOUT_CPU:
1125 sk = fanout_demux_cpu(f, skb, num); 1176 idx = fanout_demux_cpu(f, skb, num);
1177 break;
1178 case PACKET_FANOUT_ROLLOVER:
1179 idx = fanout_demux_rollover(f, skb, 0, (unsigned int) -1, num);
1126 break; 1180 break;
1127 } 1181 }
1128 1182
1129 po = pkt_sk(sk); 1183 po = pkt_sk(f->arr[idx]);
1184 if (fanout_has_flag(f, PACKET_FANOUT_FLAG_ROLLOVER) &&
1185 unlikely(!packet_rcv_has_room(po, skb))) {
1186 idx = fanout_demux_rollover(f, skb, idx, idx, num);
1187 po = pkt_sk(f->arr[idx]);
1188 }
1130 1189
1131 return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev); 1190 return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
1132} 1191}
@@ -1175,10 +1234,13 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
1175 struct packet_sock *po = pkt_sk(sk); 1234 struct packet_sock *po = pkt_sk(sk);
1176 struct packet_fanout *f, *match; 1235 struct packet_fanout *f, *match;
1177 u8 type = type_flags & 0xff; 1236 u8 type = type_flags & 0xff;
1178 u8 defrag = (type_flags & PACKET_FANOUT_FLAG_DEFRAG) ? 1 : 0; 1237 u8 flags = type_flags >> 8;
1179 int err; 1238 int err;
1180 1239
1181 switch (type) { 1240 switch (type) {
1241 case PACKET_FANOUT_ROLLOVER:
1242 if (type_flags & PACKET_FANOUT_FLAG_ROLLOVER)
1243 return -EINVAL;
1182 case PACKET_FANOUT_HASH: 1244 case PACKET_FANOUT_HASH:
1183 case PACKET_FANOUT_LB: 1245 case PACKET_FANOUT_LB:
1184 case PACKET_FANOUT_CPU: 1246 case PACKET_FANOUT_CPU:
@@ -1203,7 +1265,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
1203 } 1265 }
1204 } 1266 }
1205 err = -EINVAL; 1267 err = -EINVAL;
1206 if (match && match->defrag != defrag) 1268 if (match && match->flags != flags)
1207 goto out; 1269 goto out;
1208 if (!match) { 1270 if (!match) {
1209 err = -ENOMEM; 1271 err = -ENOMEM;
@@ -1213,7 +1275,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
1213 write_pnet(&match->net, sock_net(sk)); 1275 write_pnet(&match->net, sock_net(sk));
1214 match->id = id; 1276 match->id = id;
1215 match->type = type; 1277 match->type = type;
1216 match->defrag = defrag; 1278 match->flags = flags;
1217 atomic_set(&match->rr_cur, 0); 1279 atomic_set(&match->rr_cur, 0);
1218 INIT_LIST_HEAD(&match->list); 1280 INIT_LIST_HEAD(&match->list);
1219 spin_lock_init(&match->lock); 1281 spin_lock_init(&match->lock);
@@ -3240,7 +3302,8 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
3240 case PACKET_FANOUT: 3302 case PACKET_FANOUT:
3241 val = (po->fanout ? 3303 val = (po->fanout ?
3242 ((u32)po->fanout->id | 3304 ((u32)po->fanout->id |
3243 ((u32)po->fanout->type << 16)) : 3305 ((u32)po->fanout->type << 16) |
3306 ((u32)po->fanout->flags << 24)) :
3244 0); 3307 0);
3245 break; 3308 break;
3246 case PACKET_TX_HAS_OFF: 3309 case PACKET_TX_HAS_OFF:
diff --git a/net/packet/internal.h b/net/packet/internal.h
index e84cab8cb7a9..e891f025a1b9 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -77,10 +77,11 @@ struct packet_fanout {
77 unsigned int num_members; 77 unsigned int num_members;
78 u16 id; 78 u16 id;
79 u8 type; 79 u8 type;
80 u8 defrag; 80 u8 flags;
81 atomic_t rr_cur; 81 atomic_t rr_cur;
82 struct list_head list; 82 struct list_head list;
83 struct sock *arr[PACKET_FANOUT_MAX]; 83 struct sock *arr[PACKET_FANOUT_MAX];
84 int next[PACKET_FANOUT_MAX];
84 spinlock_t lock; 85 spinlock_t lock;
85 atomic_t sk_ref; 86 atomic_t sk_ref;
86 struct packet_type prot_hook ____cacheline_aligned_in_smp; 87 struct packet_type prot_hook ____cacheline_aligned_in_smp;