aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-17 13:48:26 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-17 13:48:26 -0400
commita6ff1a2f1e91578860b37df9fd861ef7af207de4 (patch)
tree1692579976add2fa59ab3fe008e4b0d36ec7ee30 /net/sctp
parentbd2d0837abc0206ecdd3f6b9fc8c25b55b63c96b (diff)
parent4895c771c7f006b4b90f9d6b1d2210939ba57b38 (diff)
Merge branch 'nexthop_exceptions'
These patches implement the final mechanism necessary to really allow us to go without the route cache in ipv4. We need a place to have long-term storage of PMTU/redirect information which is independent of the routes themselves, yet does not get us back into a situation where we have to write to metrics or anything like that. For this we use an "next-hop exception" table in the FIB nexthops. The one thing I desperately want to avoid is having to create clone routes in the FIB trie for this purpose, because that is very expensive. However, I'm willing to entertain such an idea later if this current scheme proves to have downsides that the FIB trie variant would not have. In order to accomodate this any such scheme, we need to be able to produce a full flow key at PMTU/redirect time. That required an adjustment of the interface call-sites used to propagate these events. For a PMTU/redirect with a fully specified socket, we pass that socket and use it to produce the flow key. Otherwise we use a passed in SKB to formulate the key. There are two cases that need to be distinguished, ICMP message processing (in which case the IP header is at skb->data) and output packet processing (mostly tunnels, and in all such cases the IP header is at ip_hdr(skb)). We also have to make the code able to handle the case where the dst itself passed into the dst_ops->{update_pmtu,redirect} method is invalidated. This matters for calls from sockets that have cached that route. We provide a inet{,6} helper function for this purpose, and edit SCTP specially since it caches routes at the transport rather than socket level. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c4
-rw-r--r--net/sctp/input.c6
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/socket.c6
-rw-r--r--net/sctp/transport.c14
5 files changed, 20 insertions, 12 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index b16517ee1aaf..8cf348e62e74 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1360,7 +1360,7 @@ struct sctp_transport *sctp_assoc_choose_alter_transport(
1360/* Update the association's pmtu and frag_point by going through all the 1360/* Update the association's pmtu and frag_point by going through all the
1361 * transports. This routine is called when a transport's PMTU has changed. 1361 * transports. This routine is called when a transport's PMTU has changed.
1362 */ 1362 */
1363void sctp_assoc_sync_pmtu(struct sctp_association *asoc) 1363void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc)
1364{ 1364{
1365 struct sctp_transport *t; 1365 struct sctp_transport *t;
1366 __u32 pmtu = 0; 1366 __u32 pmtu = 0;
@@ -1372,7 +1372,7 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
1372 list_for_each_entry(t, &asoc->peer.transport_addr_list, 1372 list_for_each_entry(t, &asoc->peer.transport_addr_list,
1373 transports) { 1373 transports) {
1374 if (t->pmtu_pending && t->dst) { 1374 if (t->pmtu_pending && t->dst) {
1375 sctp_transport_update_pmtu(t, dst_mtu(t->dst)); 1375 sctp_transport_update_pmtu(sk, t, dst_mtu(t->dst));
1376 t->pmtu_pending = 0; 1376 t->pmtu_pending = 0;
1377 } 1377 }
1378 if (!pmtu || (t->pathmtu < pmtu)) 1378 if (!pmtu || (t->pathmtu < pmtu))
diff --git a/net/sctp/input.c b/net/sctp/input.c
index f050d45faa98..c201b26879a1 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -408,10 +408,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
408 408
409 if (t->param_flags & SPP_PMTUD_ENABLE) { 409 if (t->param_flags & SPP_PMTUD_ENABLE) {
410 /* Update transports view of the MTU */ 410 /* Update transports view of the MTU */
411 sctp_transport_update_pmtu(t, pmtu); 411 sctp_transport_update_pmtu(sk, t, pmtu);
412 412
413 /* Update association pmtu. */ 413 /* Update association pmtu. */
414 sctp_assoc_sync_pmtu(asoc); 414 sctp_assoc_sync_pmtu(sk, asoc);
415 } 415 }
416 416
417 /* Retransmit with the new pmtu setting. 417 /* Retransmit with the new pmtu setting.
@@ -432,7 +432,7 @@ void sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t,
432 return; 432 return;
433 dst = sctp_transport_dst_check(t); 433 dst = sctp_transport_dst_check(t);
434 if (dst) 434 if (dst)
435 dst->ops->redirect(dst, skb); 435 dst->ops->redirect(dst, sk, skb);
436} 436}
437 437
438/* 438/*
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 539f35d07f4e..838e18b4d7ea 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -410,7 +410,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
410 if (!sctp_transport_dst_check(tp)) { 410 if (!sctp_transport_dst_check(tp)) {
411 sctp_transport_route(tp, NULL, sctp_sk(sk)); 411 sctp_transport_route(tp, NULL, sctp_sk(sk));
412 if (asoc && (asoc->param_flags & SPP_PMTUD_ENABLE)) { 412 if (asoc && (asoc->param_flags & SPP_PMTUD_ENABLE)) {
413 sctp_assoc_sync_pmtu(asoc); 413 sctp_assoc_sync_pmtu(sk, asoc);
414 } 414 }
415 } 415 }
416 dst = dst_clone(tp->dst); 416 dst = dst_clone(tp->dst);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b3b8a8d813eb..74bd3c47350a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1853,7 +1853,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
1853 } 1853 }
1854 1854
1855 if (asoc->pmtu_pending) 1855 if (asoc->pmtu_pending)
1856 sctp_assoc_pending_pmtu(asoc); 1856 sctp_assoc_pending_pmtu(sk, asoc);
1857 1857
1858 /* If fragmentation is disabled and the message length exceeds the 1858 /* If fragmentation is disabled and the message length exceeds the
1859 * association fragmentation point, return EMSGSIZE. The I-D 1859 * association fragmentation point, return EMSGSIZE. The I-D
@@ -2365,7 +2365,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
2365 if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { 2365 if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
2366 if (trans) { 2366 if (trans) {
2367 trans->pathmtu = params->spp_pathmtu; 2367 trans->pathmtu = params->spp_pathmtu;
2368 sctp_assoc_sync_pmtu(asoc); 2368 sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
2369 } else if (asoc) { 2369 } else if (asoc) {
2370 asoc->pathmtu = params->spp_pathmtu; 2370 asoc->pathmtu = params->spp_pathmtu;
2371 sctp_frag_point(asoc, params->spp_pathmtu); 2371 sctp_frag_point(asoc, params->spp_pathmtu);
@@ -2382,7 +2382,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
2382 (trans->param_flags & ~SPP_PMTUD) | pmtud_change; 2382 (trans->param_flags & ~SPP_PMTUD) | pmtud_change;
2383 if (update) { 2383 if (update) {
2384 sctp_transport_pmtu(trans, sctp_opt2sk(sp)); 2384 sctp_transport_pmtu(trans, sctp_opt2sk(sp));
2385 sctp_assoc_sync_pmtu(asoc); 2385 sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
2386 } 2386 }
2387 } else if (asoc) { 2387 } else if (asoc) {
2388 asoc->param_flags = 2388 asoc->param_flags =
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 1dcceb6e0ce6..a6b7ee9ce28a 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -228,7 +228,7 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
228 transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; 228 transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
229} 229}
230 230
231void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) 231void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu)
232{ 232{
233 struct dst_entry *dst; 233 struct dst_entry *dst;
234 234
@@ -245,8 +245,16 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
245 } 245 }
246 246
247 dst = sctp_transport_dst_check(t); 247 dst = sctp_transport_dst_check(t);
248 if (dst) 248 if (!dst)
249 dst->ops->update_pmtu(dst, pmtu); 249 t->af_specific->get_dst(t, &t->saddr, &t->fl, sk);
250
251 if (dst) {
252 dst->ops->update_pmtu(dst, sk, NULL, pmtu);
253
254 dst = sctp_transport_dst_check(t);
255 if (!dst)
256 t->af_specific->get_dst(t, &t->saddr, &t->fl, sk);
257 }
250} 258}
251 259
252/* Caches the dst entry and source address for a transport's destination 260/* Caches the dst entry and source address for a transport's destination