@@ -185,6 +185,10 @@ struct peer {
185
185
uint8_t endpoint_type ;
186
186
uint8_t medium_spec ;
187
187
} recovery ;
188
+
189
+ // Pool size
190
+ uint8_t pool_size ;
191
+ uint8_t pool_start ;
188
192
};
189
193
190
194
struct ctx {
@@ -1344,7 +1348,7 @@ static int endpoint_query_phys(struct ctx *ctx, const dest_phys *dest,
1344
1348
}
1345
1349
1346
1350
/* returns -ECONNREFUSED if the endpoint returns failure. */
1347
- static int endpoint_send_set_endpoint_id (const struct peer * peer ,
1351
+ static int endpoint_send_set_endpoint_id (struct peer * peer ,
1348
1352
mctp_eid_t * new_eidp )
1349
1353
{
1350
1354
struct sockaddr_mctp_ext addr ;
@@ -1412,9 +1416,16 @@ static int endpoint_send_set_endpoint_id(const struct peer *peer,
1412
1416
1413
1417
alloc = resp -> status & 0x3 ;
1414
1418
if (alloc != 0 ) {
1415
- // TODO for bridges
1416
- warnx ("%s requested allocation pool, unimplemented" ,
1417
- dest_phys_tostr (dest ));
1419
+ peer -> pool_size = resp -> eid_pool_size ;
1420
+ if (peer -> ctx -> verbose ) {
1421
+ fprintf (stderr ,
1422
+ "%s requested allocation of pool size = %d\n" ,
1423
+ dest_phys_tostr (dest ), peer -> pool_size );
1424
+ }
1425
+ if (peer -> pool_size > peer -> ctx -> max_pool_size ) {
1426
+ warnx ("Truncate: requested pool size > max pool size config" );
1427
+ peer -> pool_size = peer -> ctx -> max_pool_size ;
1428
+ }
1418
1429
}
1419
1430
1420
1431
rc = 0 ;
@@ -1642,11 +1653,66 @@ static int peer_set_mtu(struct ctx *ctx, struct peer *peer, uint32_t mtu)
1642
1653
return rc ;
1643
1654
}
1644
1655
1656
+ struct eid_allocation {
1657
+ mctp_eid_t start ;
1658
+ unsigned int extent ; /* 0 = only the start EID */
1659
+ };
1660
+
1661
+ /* Allocate an unused dynamic EID for a peer, optionally with an associated
1662
+ * bridge range (of size @bridged_len).
1663
+ *
1664
+ * We try to find the first allocation that contains the base EID plus the
1665
+ * full range. If no space for that exists, we return the largest
1666
+ * possible range. If the requested range is 0, then the first available
1667
+ * (single) EID will suit as a match, the returned alloc->extent will be zero.
1668
+ *
1669
+ * It is up to the caller to check whether this range is suitable, and
1670
+ * actually reserve that EID (& range) if so.
1671
+ *
1672
+ * returns 0 on success (with @alloc populated), non-zero on failure.
1673
+ */
1674
+ static int allocate_eid (struct ctx * ctx , struct net * net ,
1675
+ unsigned int bridged_len , struct eid_allocation * alloc )
1676
+ {
1677
+ struct eid_allocation cur = { 0 }, best = { 0 };
1678
+ mctp_eid_t eid ;
1679
+
1680
+ for (eid = ctx -> dyn_eid_min ; eid <= ctx -> dyn_eid_max ; eid ++ ) {
1681
+ if (net -> peers [eid ]) {
1682
+ // reset our current candidate allocation
1683
+ cur .start = 0 ;
1684
+ eid += net -> peers [eid ]-> pool_size ;
1685
+ continue ;
1686
+ }
1687
+
1688
+ // start a new candidate allocation
1689
+ if (!cur .start )
1690
+ cur .start = eid ;
1691
+ cur .extent = eid - cur .start ;
1692
+
1693
+ // if this suits, we're done
1694
+ if (cur .extent == bridged_len ) {
1695
+ * alloc = cur ;
1696
+ return 0 ;
1697
+ }
1698
+
1699
+ if (cur .extent > best .extent )
1700
+ best = cur ;
1701
+ }
1702
+
1703
+ if (best .start ) {
1704
+ * alloc = best ;
1705
+ return 0 ;
1706
+ }
1707
+
1708
+ return -1 ;
1709
+ }
1710
+
1645
1711
static int endpoint_assign_eid (struct ctx * ctx , sd_bus_error * berr ,
1646
1712
const dest_phys * dest , struct peer * * ret_peer ,
1647
- mctp_eid_t static_eid )
1713
+ mctp_eid_t static_eid , bool assign_bridge )
1648
1714
{
1649
- mctp_eid_t e , new_eid ;
1715
+ mctp_eid_t new_eid ;
1650
1716
struct net * n = NULL ;
1651
1717
struct peer * peer = NULL ;
1652
1718
uint32_t net ;
@@ -1671,22 +1737,43 @@ static int endpoint_assign_eid(struct ctx *ctx, sd_bus_error *berr,
1671
1737
1672
1738
new_eid = static_eid ;
1673
1739
} else {
1674
- /* Find an unused dynamic EID */
1675
- for (e = ctx -> dyn_eid_min ; e <= ctx -> dyn_eid_max ; e ++ ) {
1676
- if (n -> peers [e ])
1677
- continue ;
1678
- rc = add_peer (ctx , dest , e , net , & peer );
1679
- if (rc < 0 )
1680
- return rc ;
1681
- break ;
1682
- }
1683
- if (e > ctx -> dyn_eid_max ) {
1684
- warnx ("Ran out of EIDs for net %d, allocating %s" , net ,
1685
- dest_phys_tostr (dest ));
1740
+ struct eid_allocation alloc ;
1741
+ unsigned int alloc_size = 0 ;
1742
+
1743
+ if (assign_bridge )
1744
+ alloc_size = ctx -> max_pool_size ;
1745
+
1746
+ rc = allocate_eid (ctx , n , alloc_size , & alloc );
1747
+ if (rc ) {
1748
+ warnx ("Cannot allocate any EID (+pool %d) on net %d for %s" ,
1749
+ alloc_size , net , dest_phys_tostr (dest ));
1686
1750
sd_bus_error_setf (berr , SD_BUS_ERROR_FAILED ,
1687
1751
"Ran out of EIDs" );
1688
1752
return - EADDRNOTAVAIL ;
1689
1753
}
1754
+
1755
+ /* Only allow complete pools for now. In future we could reserve
1756
+ * this range, in the assumption that the subsequent pool
1757
+ * request (in the Set Endpoint ID response) will fit in this
1758
+ * reservation.
1759
+ */
1760
+ if (alloc .extent < alloc_size ) {
1761
+ warnx ("Cannot allocate sufficient EIDs (+pool %d) on net %d for %s"
1762
+ " (largest span %d at %d)" ,
1763
+ alloc_size , net , dest_phys_tostr (dest ),
1764
+ alloc .extent , alloc .start );
1765
+ alloc .extent = 0 ;
1766
+ }
1767
+
1768
+ new_eid = alloc .start ;
1769
+
1770
+ rc = add_peer (ctx , dest , new_eid , net , & peer );
1771
+ if (rc < 0 )
1772
+ return rc ;
1773
+
1774
+ peer -> pool_size = alloc .extent ;
1775
+ if (peer -> pool_size )
1776
+ peer -> pool_start = new_eid + 1 ;
1690
1777
}
1691
1778
1692
1779
rc = endpoint_send_set_endpoint_id (peer , & new_eid );
@@ -1700,6 +1787,10 @@ static int endpoint_assign_eid(struct ctx *ctx, sd_bus_error *berr,
1700
1787
}
1701
1788
1702
1789
if (new_eid != peer -> eid ) {
1790
+ // avoid allocation for any different EID in response
1791
+ warnx ("Mismatch of requested from received EID, resetting the pool" );
1792
+ peer -> pool_size = 0 ;
1793
+ peer -> pool_start = 0 ;
1703
1794
rc = change_peer_eid (peer , new_eid );
1704
1795
if (rc == - EEXIST ) {
1705
1796
sd_bus_error_setf (
@@ -2102,7 +2193,7 @@ static int method_setup_endpoint(sd_bus_message *call, void *data,
2102
2193
}
2103
2194
2104
2195
/* Set Endpoint ID */
2105
- rc = endpoint_assign_eid (ctx , berr , dest , & peer , 0 );
2196
+ rc = endpoint_assign_eid (ctx , berr , dest , & peer , 0 , false );
2106
2197
if (rc < 0 )
2107
2198
goto err ;
2108
2199
@@ -2155,21 +2246,42 @@ static int method_assign_endpoint(sd_bus_message *call, void *data,
2155
2246
peer -> net , peer_path , 0 );
2156
2247
}
2157
2248
2158
- rc = endpoint_assign_eid (ctx , berr , dest , & peer , 0 );
2249
+ rc = endpoint_assign_eid (ctx , berr , dest , & peer , 0 , true );
2159
2250
if (rc < 0 )
2160
2251
goto err ;
2161
2252
2162
2253
peer_path = path_from_peer (peer );
2163
2254
if (!peer_path )
2164
2255
goto err ;
2165
2256
2257
+ if (peer -> pool_size > 0 ) {
2258
+ //TODO: Implement Allocate EndpointID
2259
+ }
2260
+
2166
2261
return sd_bus_reply_method_return (call , "yisb" , peer -> eid , peer -> net ,
2167
2262
peer_path , 1 );
2168
2263
err :
2169
2264
set_berr (ctx , rc , berr );
2170
2265
return rc ;
2171
2266
}
2172
2267
2268
+ // Checks if given EID belongs to any bridge's pool range
2269
+ static bool is_eid_in_bridge_pool (struct net * n , struct ctx * ctx ,
2270
+ mctp_eid_t eid )
2271
+ {
2272
+ for (int i = ctx -> dyn_eid_min ; i <= eid ; i ++ ) {
2273
+ struct peer * peer = n -> peers [i ];
2274
+ if (peer && peer -> pool_size > 0 ) {
2275
+ if (eid >= peer -> pool_start &&
2276
+ eid < peer -> pool_start + peer -> pool_size ) {
2277
+ return true;
2278
+ }
2279
+ i += peer -> pool_size ;
2280
+ }
2281
+ }
2282
+ return false;
2283
+ }
2284
+
2173
2285
static int method_assign_endpoint_static (sd_bus_message * call , void * data ,
2174
2286
sd_bus_error * berr )
2175
2287
{
@@ -2224,10 +2336,22 @@ static int method_assign_endpoint_static(sd_bus_message *call, void *data,
2224
2336
return sd_bus_error_setf (berr ,
2225
2337
SD_BUS_ERROR_INVALID_ARGS ,
2226
2338
"Address in use" );
2339
+ } else {
2340
+ // is requested EID part of any bridge pool range
2341
+ struct net * n = lookup_net (ctx , netid );
2342
+ if (!n ) {
2343
+ bug_warn ("%s: Bad old net %d" , __func__ , netid );
2344
+ return - EPROTO ;
2345
+ }
2346
+ if (is_eid_in_bridge_pool (n , ctx , eid )) {
2347
+ return sd_bus_error_setf (
2348
+ berr , SD_BUS_ERROR_INVALID_ARGS ,
2349
+ "EID belongs to another MCTP bridge pool" );
2350
+ }
2227
2351
}
2228
2352
}
2229
2353
2230
- rc = endpoint_assign_eid (ctx , berr , dest , & peer , eid );
2354
+ rc = endpoint_assign_eid (ctx , berr , dest , & peer , eid , false );
2231
2355
if (rc < 0 ) {
2232
2356
goto err ;
2233
2357
}
@@ -2637,7 +2761,8 @@ static int peer_endpoint_recover(sd_event_source *s, uint64_t usec,
2637
2761
* after which we immediately return as there's no old peer state left to
2638
2762
* maintain.
2639
2763
*/
2640
- return endpoint_assign_eid (ctx , NULL , & phys , & peer , 0 );
2764
+ return endpoint_assign_eid (ctx , NULL , & phys , & peer , 0 ,
2765
+ false);
2641
2766
}
2642
2767
2643
2768
/* Confirmation of the same device, apply its already allocated EID */
0 commit comments