pinctrl enqueues PACKET_OUT and NXT_RESUME messages on rconn.txq with
no limit.  A PACKET_IN storm (ARP, ND, etc.) could grow the queue
without bound and use a large amount of memory.

Limit PACKET_IN driven PACKET_OUT and NXT_RESUME messages to 8192.
Overflows are counted by the pinctrl_drop_rconn_overflow coverage
counter.  The limit does not apply to OpenFlow session control messages,
MAC-binding buffered resumes, health-check probes, BFD and other
controller originated packets.

Acked-by: Aditya Mehakare <[email protected]>
Assisted-by: Cursor Grok 4.6, Cursor
Signed-off-by: Naveen Yerramneni <[email protected]>
---
 controller/pinctrl.c | 48 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 216831e6e..ed903fc90 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -16,6 +16,8 @@
 
 #include <config.h>
 
+#include <errno.h>
+
 #include "pinctrl.h"
 
 #include "coverage.h"
@@ -172,6 +174,9 @@ static struct seq *pinctrl_handler_seq;
 static struct seq *pinctrl_main_seq;
 static uint64_t main_seq;
 
+/* Limit of tx packets can be queued on rconn.txq. */
+#define PINCTRL_QUEUE_TX_PKT_LIMIT 8192
+
 #define ARP_ND_DEF_MAX_TIMEOUT    16000
 
 static long long int arp_nd_max_timeout = ARP_ND_DEF_MAX_TIMEOUT;
@@ -182,6 +187,8 @@ static void *pinctrl_handler(void *arg);
 struct pinctrl {
     /* OpenFlow connection to the switch. */
     struct rconn *swconn;
+    /* Counts tx packets queued on swconn. */
+    struct rconn_packet_counter *tx_pending_counter;
     pthread_t pinctrl_thread;
     /* Latch to destroy the 'pinctrl_thread' */
     struct latch pinctrl_thread_exit;
@@ -397,6 +404,7 @@ COVERAGE_DEFINE(pinctrl_ring_full_put_fdb);
 COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map);
 COVERAGE_DEFINE(pinctrl_drop_controller_event);
 COVERAGE_DEFINE(pinctrl_drop_put_vport_binding);
+COVERAGE_DEFINE(pinctrl_drop_rconn_overflow);
 COVERAGE_DEFINE(pinctrl_notify_main_thread);
 COVERAGE_DEFINE(pinctrl_notify_handler_thread);
 COVERAGE_DEFINE(pinctrl_total_pin_pkts);
@@ -580,6 +588,7 @@ pinctrl_init(void)
     bfd_monitor_init();
     init_fdb_entries();
     pinctrl.swconn = rconn_create(0, 0, DSCP_DEFAULT, 1 << OFP15_VERSION);
+    pinctrl.tx_pending_counter = rconn_packet_counter_create();
     pinctrl.mac_binding_can_timestamp = false;
     pinctrl_handler_seq = seq_create();
     pinctrl_main_seq = seq_create();
@@ -600,6 +609,15 @@ queue_msg(struct rconn *swconn, struct ofpbuf *msg)
     return xid;
 }
 
+static void
+queue_msg_with_limit(struct rconn *swconn, struct ofpbuf *msg)
+{
+    if (rconn_send_with_limit(swconn, msg, pinctrl.tx_pending_counter,
+                              PINCTRL_QUEUE_TX_PKT_LIMIT) == EAGAIN) {
+        COVERAGE_INC(pinctrl_drop_rconn_overflow);
+    }
+}
+
 /* Sets up 'swconn', a newly (re)connected connection to a switch. */
 static void
 pinctrl_setup(struct rconn *swconn)
@@ -639,7 +657,7 @@ enqueue_packet(struct rconn *swconn, enum ofp_version 
version,
 
     match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
-    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+    queue_msg_with_limit(swconn, ofputil_encode_packet_out(&po, proto));
 }
 
 static void
@@ -751,7 +769,7 @@ pinctrl_forward_pkt(struct rconn *swconn, int64_t dp_key,
     };
     match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
-    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+    queue_msg_with_limit(swconn, ofputil_encode_packet_out(&po, proto));
     ofpbuf_uninit(&ofpacts);
 }
 
@@ -1045,7 +1063,7 @@ pinctrl_parse_dhcpv6_advt(struct rconn *swconn, const 
struct flow *ip_flow,
     };
     match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
-    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+    queue_msg_with_limit(swconn, ofputil_encode_packet_out(&po, proto));
     dp_packet_uninit(&packet);
     ofpbuf_uninit(&ofpacts);
 
@@ -2382,7 +2400,8 @@ exit:
         sv.u8_val = success;
         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     if (pkt_out_ptr) {
         dp_packet_uninit(pkt_out_ptr);
     }
@@ -2594,7 +2613,8 @@ exit:
         sv.u8_val = success;
         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     if (pkt_out_ptr) {
         dp_packet_uninit(pkt_out_ptr);
     }
@@ -2934,7 +2954,8 @@ exit:
         sv.u8_val = success;
         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     if (pkt_out_ptr) {
         dp_packet_uninit(pkt_out_ptr);
     }
@@ -3360,7 +3381,8 @@ exit:
         sv.u8_val = success;
         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     dp_packet_uninit(pkt_out_ptr);
 }
 
@@ -3740,7 +3762,8 @@ exit:
         set_from_ctrl_flag_in_pkt_metadata(pin);
 
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     dp_packet_uninit(pkt_out_ptr);
 }
 
@@ -4781,6 +4804,7 @@ pinctrl_destroy(void)
     pthread_join(pinctrl.pinctrl_thread, NULL);
     latch_destroy(&pinctrl.pinctrl_thread_exit);
     rconn_destroy(pinctrl.swconn);
+    rconn_packet_counter_destroy(pinctrl.tx_pending_counter);
     destroy_send_arps_nds();
     destroy_ipv6_ras();
     destroy_ipv6_prefixd();
@@ -6691,7 +6715,8 @@ exit:
         sv.u8_val = success;
         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     }
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     dp_packet_uninit(pkt_out_ptr);
 }
 
@@ -6804,7 +6829,8 @@ pinctrl_handle_put_icmp4_inner_ip4_src(struct rconn 
*swconn,
     pin->packet_len = dp_packet_size(pkt_out);
 
 exit:
-    queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
+    queue_msg_with_limit(swconn,
+                         ofputil_encode_resume(pin, continuation, proto));
     if (pkt_out) {
         dp_packet_delete(pkt_out);
     }
@@ -9029,7 +9055,7 @@ pinctrl_split_buf_action_handler(struct rconn *swconn, 
struct dp_packet *pkt,
     match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
     enum ofp_version version = rconn_get_version(swconn);
     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
-    queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+    queue_msg_with_limit(swconn, ofputil_encode_packet_out(&po, proto));
 
     ofpbuf_uninit(&ofpacts);
 }
-- 
2.43.5

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to