@@ -101,6 +101,12 @@ struct role {
101101 const char * dbus_val ;
102102};
103103
104+ // Endpoint poll context for bridged endpoint polling
105+ struct ep_poll_ctx {
106+ struct peer * bridge ;
107+ mctp_eid_t poll_eid ;
108+ };
109+
104110static const struct role roles [] = {
105111 [ENDPOINT_ROLE_UNKNOWN ] = {
106112 .role = ENDPOINT_ROLE_UNKNOWN ,
@@ -199,6 +205,10 @@ struct peer {
199205 // Pool size
200206 uint8_t pool_size ;
201207 uint8_t pool_start ;
208+
209+ struct {
210+ sd_event_source * * sources ;
211+ } bridge_ep_poll ;
202212};
203213
204214struct msg_type_support {
@@ -284,6 +294,7 @@ static int add_peer_from_addr(struct ctx *ctx,
284294 const struct sockaddr_mctp_ext * addr ,
285295 struct peer * * ret_peer );
286296static int remove_peer (struct peer * peer );
297+ static int remove_bridged_peers (struct peer * bridge );
287298static int query_peer_properties (struct peer * peer );
288299static int setup_added_peer (struct peer * peer );
289300static void add_peer_route (struct peer * peer );
@@ -1963,6 +1974,57 @@ static int check_peer_struct(const struct peer *peer, const struct net *n)
19631974 return 0 ;
19641975}
19651976
1977+ /* Stops downstream endpoint polling and removes
1978+ * peer structure when bridge endpoint is being removed.
1979+ */
1980+ static int remove_bridged_peers (struct peer * bridge )
1981+ {
1982+ mctp_eid_t ep , pool_start , pool_end ;
1983+ struct ep_poll_ctx * pctx = NULL ;
1984+ struct peer * peer = NULL ;
1985+ struct net * n = NULL ;
1986+ int rc = 0 ;
1987+
1988+ pool_end = bridge -> pool_start + bridge -> pool_size - 1 ;
1989+ n = lookup_net (bridge -> ctx , bridge -> net );
1990+ pool_start = bridge -> pool_start ;
1991+ for (ep = pool_start ; ep <= pool_end ; ep ++ ) {
1992+ // stop endpoint polling before removing peer
1993+ // else next trigger will create peer again.
1994+ int idx = ep - pool_start ;
1995+
1996+ if (bridge -> bridge_ep_poll .sources &&
1997+ bridge -> bridge_ep_poll .sources [idx ]) {
1998+ pctx = sd_event_source_get_userdata (
1999+ bridge -> bridge_ep_poll .sources [idx ]);
2000+ rc = sd_event_source_set_enabled (
2001+ bridge -> bridge_ep_poll .sources [idx ],
2002+ SD_EVENT_OFF );
2003+ if (rc < 0 ) {
2004+ warnx ("Failed to stop polling timer while removing peer %d: %s" ,
2005+ ep , strerror (- rc ));
2006+ }
2007+
2008+ sd_event_source_unref (
2009+ bridge -> bridge_ep_poll .sources [idx ]);
2010+ bridge -> bridge_ep_poll .sources [idx ] = NULL ;
2011+ free (pctx );
2012+ }
2013+ peer = n -> peers [ep ];
2014+ if (!peer )
2015+ continue ;
2016+
2017+ rc = remove_peer (peer );
2018+ if (rc < 0 ) {
2019+ warnx ("Failed to remove peer %d from bridge eid %d pool [%d - %d]: %s" ,
2020+ ep , bridge -> eid , pool_start , pool_end ,
2021+ strerror (- rc ));
2022+ }
2023+ }
2024+
2025+ return 0 ;
2026+ }
2027+
19662028static int remove_peer (struct peer * peer )
19672029{
19682030 struct ctx * ctx = peer -> ctx ;
@@ -1997,6 +2059,12 @@ static int remove_peer(struct peer *peer)
19972059 sd_event_source_unref (peer -> recovery .source );
19982060 }
19992061
2062+ if (peer -> pool_size ) {
2063+ remove_bridged_peers (peer );
2064+ free (peer -> bridge_ep_poll .sources );
2065+ peer -> bridge_ep_poll .sources = NULL ;
2066+ }
2067+
20002068 n -> peers [peer -> eid ] = NULL ;
20012069 free (peer -> message_types );
20022070 free (peer -> uuid );
@@ -2043,6 +2111,7 @@ static void free_peers(struct ctx *ctx)
20432111 free (peer -> message_types );
20442112 free (peer -> uuid );
20452113 free (peer -> path );
2114+ free (peer -> bridge_ep_poll .sources );
20462115 sd_bus_slot_unref (peer -> slot_obmc_endpoint );
20472116 sd_bus_slot_unref (peer -> slot_cc_endpoint );
20482117 sd_bus_slot_unref (peer -> slot_bridge );
@@ -2446,6 +2515,52 @@ static int get_endpoint_peer(struct ctx *ctx, sd_bus_error *berr,
24462515 return 0 ;
24472516}
24482517
2518+ /* DSP0236 section 8.17.6 Reclaiming EIDs from hot-plug devices
2519+ *
2520+ * The bus owner/bridge can detect a removed device or devices by
2521+ * validating the EIDs that are presently allocated to endpoints that
2522+ * are directly on the bus and identifying which EIDs are missing.
2523+ * It can do this by attempting to access each endpoint that the bridge
2524+ * has listed in its routing table as being a device that is directly on
2525+ * the particular bus. Attempting to access each endpoint can be accomplished
2526+ * by issuing the Get Endpoint ID command...
2527+
2528+
2529+ * since bridged endpoints are routed from bridge, direct query
2530+ * to eid should work if gateway routes are in place.
2531+ */
2532+ static int query_endpoint_poll_commmand (struct peer * peer , mctp_eid_t * resp_eid )
2533+ {
2534+ struct sockaddr_mctp_ext addr = { 0 };
2535+ struct mctp_ctrl_cmd_get_eid req = { 0 };
2536+ struct mctp_ctrl_resp_get_eid * resp = NULL ;
2537+
2538+ uint8_t * buf = NULL ;
2539+ size_t buf_size ;
2540+ uint8_t iid ;
2541+ int rc ;
2542+
2543+ iid = mctp_next_iid (peer -> ctx );
2544+ mctp_ctrl_msg_hdr_init_req (& req .ctrl_hdr , iid ,
2545+ MCTP_CTRL_CMD_GET_ENDPOINT_ID );
2546+ rc = endpoint_query_peer (peer , MCTP_CTRL_HDR_MSG_TYPE , & req ,
2547+ sizeof (req ), & buf , & buf_size , & addr );
2548+ if (rc < 0 )
2549+ goto out ;
2550+
2551+ rc = mctp_ctrl_validate_response (buf , buf_size , sizeof (* resp ),
2552+ peer_tostr_short (peer ), iid ,
2553+ MCTP_CTRL_CMD_GET_ENDPOINT_ID );
2554+ if (!rc ) {
2555+ resp = (void * )buf ;
2556+ * resp_eid = resp -> eid ;
2557+ }
2558+
2559+ out :
2560+ free (buf );
2561+ return rc ;
2562+ }
2563+
24492564static int query_get_peer_msgtypes (struct peer * peer )
24502565{
24512566 struct sockaddr_mctp_ext addr ;
@@ -5213,6 +5328,139 @@ static int endpoint_send_allocate_endpoint_ids(
52135328 return rc ;
52145329}
52155330
5331+ static int peer_endpoint_poll (sd_event_source * s , uint64_t usec , void * userdata )
5332+ {
5333+ struct ep_poll_ctx * pctx = userdata ;
5334+ struct peer * bridge = pctx -> bridge ;
5335+ mctp_eid_t ep = pctx -> poll_eid ;
5336+ mctp_eid_t pool_start , idx ;
5337+ struct peer * peer = NULL ;
5338+ mctp_eid_t ret_eid = 0 ;
5339+ struct net * n ;
5340+ int rc = 0 ;
5341+
5342+ if (!bridge ) {
5343+ free (pctx );
5344+ return 0 ;
5345+ }
5346+
5347+ pool_start = bridge -> pool_start ;
5348+ idx = ep - pool_start ;
5349+
5350+ /* Polling policy :
5351+ *
5352+ * Once bridge eid pool space is allocated and gateway
5353+ * routes for downstream endpoints are in place, busowner
5354+ * would initiate periodic GET_ENDPOINT_ID command at an
5355+ * interval of atleast 1/2 * TRECLAIM.
5356+
5357+ 1. The downstream endpoint if present behind the bridge,
5358+ responds to send poll command, that endpoint path is
5359+ considered accessible.
5360+ The endpoint path would be published as reachable to d-bus and
5361+ polling will no longer continue.
5362+
5363+ 2. If endpoint is not present or doesn't responds to send poll
5364+ commmand, then it has not been establed yet that endpoint
5365+ path from the bridge is accessible or not, thus continue
5366+ to poll.
5367+ */
5368+
5369+ n = lookup_net (bridge -> ctx , bridge -> net );
5370+ peer = n -> peers [ep ];
5371+ if (!peer ) {
5372+ rc = add_peer (bridge -> ctx , & (bridge -> phys ), ep , bridge -> net ,
5373+ & peer , true);
5374+ if (rc < 0 )
5375+ goto exit ;
5376+ }
5377+
5378+ rc = query_endpoint_poll_commmand (peer , & ret_eid );
5379+ if (rc < 0 ) {
5380+ goto reschedule ;
5381+ }
5382+
5383+ if (ret_eid != ep ) {
5384+ warnx ("Unexpected eid %d abort polling for eid %d" , ret_eid ,
5385+ ep );
5386+ goto exit ;
5387+ }
5388+
5389+ if (bridge -> ctx -> verbose ) {
5390+ fprintf (stderr , "Endpoint %d is accessible\n" , ep );
5391+ }
5392+
5393+ rc = setup_added_peer (peer );
5394+ if (rc < 0 )
5395+ goto reschedule ;
5396+
5397+ exit :
5398+ if (bridge ) {
5399+ assert (sd_event_source_get_enabled (
5400+ bridge -> bridge_ep_poll .sources [idx ], NULL ) == 0 );
5401+ sd_event_source_unref (bridge -> bridge_ep_poll .sources [idx ]);
5402+ bridge -> bridge_ep_poll .sources [idx ] = NULL ;
5403+ }
5404+ free (pctx );
5405+ return rc < 0 ? rc : 0 ;
5406+
5407+ reschedule :
5408+ rc = mctp_ops .sd_event .source_set_time_relative (
5409+ bridge -> bridge_ep_poll .sources [idx ],
5410+ bridge -> ctx -> endpoint_poll );
5411+ if (rc >= 0 ) {
5412+ rc = sd_event_source_set_enabled (
5413+ bridge -> bridge_ep_poll .sources [idx ], SD_EVENT_ONESHOT );
5414+ }
5415+ return 0 ;
5416+ }
5417+
5418+ static int bridge_poll_start (struct peer * bridge )
5419+ {
5420+ mctp_eid_t pool_start = bridge -> pool_start ;
5421+ mctp_eid_t pool_size = bridge -> pool_size ;
5422+ sd_event_source * * sources = NULL ;
5423+ struct ctx * ctx ;
5424+ int rc ;
5425+ int i ;
5426+
5427+ sources = calloc (pool_size , sizeof (sd_event_source * ));
5428+ ctx = bridge -> ctx ;
5429+
5430+ if (!sources ) {
5431+ rc = - ENOMEM ;
5432+ warnx ("Failed to setup periodic polling for bridge (eid %d)" ,
5433+ bridge -> eid );
5434+ return rc ;
5435+ }
5436+
5437+ bridge -> bridge_ep_poll .sources = sources ;
5438+ for (i = 0 ; i < pool_size ; i ++ ) {
5439+ struct ep_poll_ctx * pctx =
5440+ calloc (1 , sizeof (struct ep_poll_ctx ));
5441+ if (!pctx ) {
5442+ warnx ("Failed to memory, skip polling for eid %d" ,
5443+ pool_start + i );
5444+ continue ;
5445+ }
5446+
5447+ pctx -> bridge = bridge ;
5448+ pctx -> poll_eid = pool_start + i ;
5449+ rc = mctp_ops .sd_event .add_time_relative (
5450+ ctx -> event , & bridge -> bridge_ep_poll .sources [i ],
5451+ CLOCK_MONOTONIC , ctx -> endpoint_poll , 0 ,
5452+ peer_endpoint_poll , pctx );
5453+ if (rc < 0 ) {
5454+ warnx ("Failed to setup poll event source for eid %d" ,
5455+ (pool_start + i ));
5456+ free (pctx );
5457+ continue ;
5458+ }
5459+ }
5460+
5461+ return 0 ;
5462+ }
5463+
52165464static int endpoint_allocate_eids (struct peer * peer )
52175465{
52185466 uint8_t allocated_pool_size = 0 ;
@@ -5281,7 +5529,10 @@ static int endpoint_allocate_eids(struct peer *peer)
52815529 peer -> pool_size );
52825530 }
52835531
5284- // TODO: Polling logic for downstream EID
5532+ // Poll for downstream endpoint accessibility
5533+ if (peer -> ctx -> endpoint_poll ) {
5534+ bridge_poll_start (peer );
5535+ }
52855536
52865537 return 0 ;
52875538}
0 commit comments