diff --git a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/buffers_defaults_t2.j2 b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/buffers_defaults_t2.j2 index 8f9293ded3..3634f2149f 100644 --- a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/buffers_defaults_t2.j2 +++ b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/buffers_defaults_t2.j2 @@ -15,13 +15,7 @@ {%- macro generate_port_lists(PORT_ALL) %} {# Generate list of ports #} - {%- for port_idx in range(0,128,8) %} - {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} - {%- endfor %} - {%- for port_idx in range(128,256,4) %} - {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} - {%- endfor %} - {%- for port_idx in range(256,384,8) %} + {%- for port_idx in range(0,256,4) %} {%- if PORT_ALL.append("Ethernet%d" % (port_idx)) %}{%- endif %} {%- endfor %} {%- endmacro %} diff --git a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/gearbox_config.json b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/gearbox_config.json index 0b3d13650a..7bac6d8cb6 100644 --- a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/gearbox_config.json +++ b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/gearbox_config.json @@ -264,7 +264,7 @@ ] }, { - "name": "Ethernet8", + "name": "Ethernet4", "index": 2, "phy_id": 1, "system_lanes": [ @@ -285,7 +285,7 @@ ] }, { - "name": "Ethernet16", + "name": "Ethernet8", "index": 3, "phy_id": 2, "system_lanes": [ @@ -306,7 +306,7 @@ ] }, { - "name": "Ethernet24", + "name": "Ethernet12", "index": 4, "phy_id": 2, "system_lanes": [ @@ -327,7 +327,7 @@ ] }, { - "name": "Ethernet32", + "name": "Ethernet16", "index": 5, "phy_id": 3, "system_lanes": [ @@ -348,7 +348,7 @@ ] }, { - "name": "Ethernet40", + "name": "Ethernet20", "index": 6, "phy_id": 3, "system_lanes": [ @@ -369,7 +369,7 @@ ] }, { - "name": "Ethernet48", + "name": "Ethernet24", "index": 7, "phy_id": 4, "system_lanes": [ @@ -390,7 +390,7 @@ ] }, { - "name": "Ethernet56", + "name": "Ethernet28", "index": 8, "phy_id": 4, "system_lanes": [ @@ -411,7 +411,7 @@ ] }, { - "name": "Ethernet64", + "name": "Ethernet32", "index": 9, "phy_id": 5, "system_lanes": [ @@ -432,7 +432,7 @@ ] }, { - "name": "Ethernet72", + "name": "Ethernet36", "index": 10, "phy_id": 5, "system_lanes": [ @@ -453,7 +453,7 @@ ] }, { - "name": "Ethernet80", + "name": "Ethernet40", "index": 11, "phy_id": 7, "system_lanes": [ @@ -474,7 +474,7 @@ ] }, { - "name": "Ethernet88", + "name": "Ethernet44", "index": 12, "phy_id": 7, "system_lanes": [ @@ -495,7 +495,7 @@ ] }, { - "name": "Ethernet96", + "name": "Ethernet48", "index": 13, "phy_id": 6, "system_lanes": [ @@ -516,7 +516,7 @@ ] }, { - "name": "Ethernet104", + "name": "Ethernet52", "index": 14, "phy_id": 6, "system_lanes": [ @@ -537,7 +537,7 @@ ] }, { - "name": "Ethernet112", + "name": "Ethernet56", "index": 15, "phy_id": 8, "system_lanes": [ @@ -558,7 +558,7 @@ ] }, { - "name": "Ethernet120", + "name": "Ethernet60", "index": 16, "phy_id": 8, "system_lanes": [ @@ -579,7 +579,7 @@ ] }, { - "name": "Ethernet256", + "name": "Ethernet192", "index": 49, "phy_id": 9, "system_lanes": [ @@ -600,7 +600,7 @@ ] }, { - "name": "Ethernet264", + "name": "Ethernet196", "index": 50, "phy_id": 9, "system_lanes": [ @@ -621,7 +621,7 @@ ] }, { - "name": "Ethernet272", + "name": "Ethernet200", "index": 51, "phy_id": 11, "system_lanes": [ @@ -642,7 +642,7 @@ ] }, { - "name": "Ethernet280", + "name": "Ethernet204", "index": 52, "phy_id": 11, "system_lanes": [ @@ -663,7 +663,7 @@ ] }, { - "name": "Ethernet288", + "name": "Ethernet208", "index": 53, "phy_id": 14, "system_lanes": [ @@ -684,7 +684,7 @@ ] }, { - "name": "Ethernet296", + "name": "Ethernet212", "index": 54, "phy_id": 14, "system_lanes": [ @@ -705,7 +705,7 @@ ] }, { - "name": "Ethernet304", + "name": "Ethernet216", "index": 55, "phy_id": 10, "system_lanes": [ @@ -726,7 +726,7 @@ ] }, { - "name": "Ethernet312", + "name": "Ethernet220", "index": 56, "phy_id": 10, "system_lanes": [ @@ -747,7 +747,7 @@ ] }, { - "name": "Ethernet320", + "name": "Ethernet224", "index": 57, "phy_id": 12, "system_lanes": [ @@ -768,7 +768,7 @@ ] }, { - "name": "Ethernet328", + "name": "Ethernet228", "index": 58, "phy_id": 12, "system_lanes": [ @@ -789,7 +789,7 @@ ] }, { - "name": "Ethernet336", + "name": "Ethernet232", "index": 59, "phy_id": 13, "system_lanes": [ @@ -810,7 +810,7 @@ ] }, { - "name": "Ethernet344", + "name": "Ethernet236", "index": 60, "phy_id": 13, "system_lanes": [ @@ -831,7 +831,7 @@ ] }, { - "name": "Ethernet352", + "name": "Ethernet240", "index": 61, "phy_id": 15, "system_lanes": [ @@ -852,7 +852,7 @@ ] }, { - "name": "Ethernet360", + "name": "Ethernet244", "index": 62, "phy_id": 15, "system_lanes": [ @@ -873,7 +873,7 @@ ] }, { - "name": "Ethernet368", + "name": "Ethernet248", "index": 63, "phy_id": 16, "system_lanes": [ @@ -894,7 +894,7 @@ ] }, { - "name": "Ethernet376", + "name": "Ethernet252", "index": 64, "phy_id": 16, "system_lanes": [ diff --git a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/port_config.ini b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/port_config.ini index bcc91ee4c5..75c7de14b3 100644 --- a/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/port_config.ini +++ b/device/arista/x86_64-arista_7280r4_32qf_32df/Arista-7280R4-32QF-32DF-64O/port_config.ini @@ -1,66 +1,66 @@ # name lanes alias index role speed asic_port_name core_id core_port_id num_voq Ethernet0 35,34,33,32 etp1 1 Ext 400000 Eth0 1 1 8 -Ethernet8 37,36,39,38 etp2 2 Ext 400000 Eth8 1 2 8 -Ethernet16 40,41,42,43 etp3 3 Ext 400000 Eth16 1 3 8 -Ethernet24 46,47,44,45 etp4 4 Ext 400000 Eth24 1 4 8 -Ethernet32 50,51,48,49 etp5 5 Ext 400000 Eth32 1 5 8 -Ethernet40 52,53,54,55 etp6 6 Ext 400000 Eth40 1 6 8 -Ethernet48 56,57,58,59 etp7 7 Ext 400000 Eth48 1 7 8 -Ethernet56 62,63,60,61 etp8 8 Ext 400000 Eth56 1 8 8 -Ethernet64 123,122,121,120 etp9 9 Ext 400000 Eth64 3 9 8 -Ethernet72 125,124,127,126 etp10 10 Ext 400000 Eth72 3 10 8 -Ethernet80 96,97,98,99 etp11 11 Ext 400000 Eth80 3 11 8 -Ethernet88 102,103,100,101 etp12 12 Ext 400000 Eth88 3 12 8 -Ethernet96 114,115,112,113 etp13 13 Ext 400000 Eth96 3 13 8 -Ethernet104 116,117,118,119 etp14 14 Ext 400000 Eth104 3 14 8 -Ethernet112 104,105,106,107 etp15 15 Ext 400000 Eth112 3 15 8 -Ethernet120 110,111,108,109 etp16 16 Ext 400000 Eth120 3 16 8 -Ethernet128 72,73,74,75 etp17 17 Ext 400000 Eth128 2 17 8 -Ethernet132 76,77,78,79 etp18 18 Ext 400000 Eth132 2 18 8 -Ethernet136 64,65,66,67 etp19 19 Ext 400000 Eth136 2 19 8 -Ethernet140 68,69,70,71 etp20 20 Ext 400000 Eth140 2 20 8 -Ethernet144 88,89,90,91 etp21 21 Ext 400000 Eth144 2 21 8 -Ethernet148 92,93,94,95 etp22 22 Ext 400000 Eth148 2 22 8 -Ethernet152 80,81,82,83 etp23 23 Ext 400000 Eth152 2 23 8 -Ethernet156 84,85,86,87 etp24 24 Ext 400000 Eth156 2 24 8 -Ethernet160 16,17,18,19 etp25 25 Ext 400000 Eth160 0 25 8 -Ethernet164 20,21,22,23 etp26 26 Ext 400000 Eth164 0 26 8 -Ethernet168 24,25,26,27 etp27 27 Ext 400000 Eth168 0 27 8 -Ethernet172 28,29,30,31 etp28 28 Ext 400000 Eth172 0 28 8 -Ethernet176 0,1,2,3 etp29 29 Ext 400000 Eth176 0 29 8 -Ethernet180 4,5,6,7 etp30 30 Ext 400000 Eth180 0 30 8 -Ethernet184 8,9,10,11 etp31 31 Ext 400000 Eth184 0 31 8 -Ethernet188 12,13,14,15 etp32 32 Ext 400000 Eth188 0 32 8 -Ethernet192 168,169,170,171 etp33 33 Ext 400000 Eth192 5 33 8 -Ethernet196 172,173,174,175 etp34 34 Ext 400000 Eth196 5 34 8 -Ethernet200 160,161,162,163 etp35 35 Ext 400000 Eth200 5 35 8 -Ethernet204 164,165,166,167 etp36 36 Ext 400000 Eth204 5 36 8 -Ethernet208 184,185,186,187 etp37 37 Ext 400000 Eth208 5 37 8 -Ethernet212 188,189,190,191 etp38 38 Ext 400000 Eth212 5 38 8 -Ethernet216 176,177,178,179 etp39 39 Ext 400000 Eth216 5 39 8 -Ethernet220 180,181,182,183 etp40 40 Ext 400000 Eth220 5 40 8 -Ethernet224 248,249,250,251 etp41 41 Ext 400000 Eth224 7 41 8 -Ethernet228 252,253,254,255 etp42 42 Ext 400000 Eth228 7 42 8 -Ethernet232 240,241,242,243 etp43 43 Ext 400000 Eth232 7 43 8 -Ethernet236 244,245,246,247 etp44 44 Ext 400000 Eth236 7 44 8 -Ethernet240 232,233,234,235 etp45 45 Ext 400000 Eth240 7 45 8 -Ethernet244 236,237,238,239 etp46 46 Ext 400000 Eth244 7 46 8 -Ethernet248 224,225,226,227 etp47 47 Ext 400000 Eth248 7 47 8 -Ethernet252 228,229,230,231 etp48 48 Ext 400000 Eth252 7 48 8 -Ethernet256 210,211,208,209 etp49 49 Ext 400000 Eth256 6 49 8 -Ethernet264 212,213,214,215 etp50 50 Ext 400000 Eth264 6 50 8 -Ethernet272 200,201,202,203 etp51 51 Ext 400000 Eth272 6 51 8 -Ethernet280 206,207,204,205 etp52 52 Ext 400000 Eth280 6 52 8 -Ethernet288 219,218,217,216 etp53 53 Ext 400000 Eth288 6 53 8 -Ethernet296 221,220,223,222 etp54 54 Ext 400000 Eth296 6 54 8 -Ethernet304 192,193,194,195 etp55 55 Ext 400000 Eth304 6 55 8 -Ethernet312 198,199,196,197 etp56 56 Ext 400000 Eth312 6 56 8 -Ethernet320 154,155,152,153 etp57 57 Ext 400000 Eth320 4 57 8 -Ethernet328 156,157,158,159 etp58 58 Ext 400000 Eth328 4 58 8 -Ethernet336 144,145,146,147 etp59 59 Ext 400000 Eth336 4 59 8 -Ethernet344 150,151,148,149 etp60 60 Ext 400000 Eth344 4 60 8 -Ethernet352 139,138,137,136 etp61 61 Ext 400000 Eth352 4 61 8 -Ethernet360 141,140,143,142 etp62 62 Ext 400000 Eth360 4 62 8 -Ethernet368 128,129,130,131 etp63 63 Ext 400000 Eth368 4 63 8 -Ethernet376 134,135,132,133 etp64 64 Ext 400000 Eth376 4 64 8 +Ethernet4 37,36,39,38 etp2 2 Ext 400000 Eth4 1 2 8 +Ethernet8 40,41,42,43 etp3 3 Ext 400000 Eth8 1 3 8 +Ethernet12 46,47,44,45 etp4 4 Ext 400000 Eth12 1 4 8 +Ethernet16 50,51,48,49 etp5 5 Ext 400000 Eth16 1 5 8 +Ethernet20 52,53,54,55 etp6 6 Ext 400000 Eth20 1 6 8 +Ethernet24 56,57,58,59 etp7 7 Ext 400000 Eth24 1 7 8 +Ethernet28 62,63,60,61 etp8 8 Ext 400000 Eth28 1 8 8 +Ethernet32 123,122,121,120 etp9 9 Ext 400000 Eth32 3 9 8 +Ethernet36 125,124,127,126 etp10 10 Ext 400000 Eth36 3 10 8 +Ethernet40 96,97,98,99 etp11 11 Ext 400000 Eth40 3 11 8 +Ethernet44 102,103,100,101 etp12 12 Ext 400000 Eth44 3 12 8 +Ethernet48 114,115,112,113 etp13 13 Ext 400000 Eth48 3 13 8 +Ethernet52 116,117,118,119 etp14 14 Ext 400000 Eth52 3 14 8 +Ethernet56 104,105,106,107 etp15 15 Ext 400000 Eth56 3 15 8 +Ethernet60 110,111,108,109 etp16 16 Ext 400000 Eth60 3 16 8 +Ethernet64 72,73,74,75 etp17 17 Ext 400000 Eth64 2 17 8 +Ethernet68 76,77,78,79 etp18 18 Ext 400000 Eth68 2 18 8 +Ethernet72 64,65,66,67 etp19 19 Ext 400000 Eth72 2 19 8 +Ethernet76 68,69,70,71 etp20 20 Ext 400000 Eth76 2 20 8 +Ethernet80 88,89,90,91 etp21 21 Ext 400000 Eth80 2 21 8 +Ethernet84 92,93,94,95 etp22 22 Ext 400000 Eth84 2 22 8 +Ethernet88 80,81,82,83 etp23 23 Ext 400000 Eth88 2 23 8 +Ethernet92 84,85,86,87 etp24 24 Ext 400000 Eth92 2 24 8 +Ethernet96 16,17,18,19 etp25 25 Ext 400000 Eth96 0 25 8 +Ethernet100 20,21,22,23 etp26 26 Ext 400000 Eth100 0 26 8 +Ethernet104 24,25,26,27 etp27 27 Ext 400000 Eth104 0 27 8 +Ethernet108 28,29,30,31 etp28 28 Ext 400000 Eth108 0 28 8 +Ethernet112 0,1,2,3 etp29 29 Ext 400000 Eth112 0 29 8 +Ethernet116 4,5,6,7 etp30 30 Ext 400000 Eth116 0 30 8 +Ethernet120 8,9,10,11 etp31 31 Ext 400000 Eth120 0 31 8 +Ethernet124 12,13,14,15 etp32 32 Ext 400000 Eth124 0 32 8 +Ethernet128 168,169,170,171 etp33 33 Ext 400000 Eth128 5 33 8 +Ethernet132 172,173,174,175 etp34 34 Ext 400000 Eth132 5 34 8 +Ethernet136 160,161,162,163 etp35 35 Ext 400000 Eth136 5 35 8 +Ethernet140 164,165,166,167 etp36 36 Ext 400000 Eth140 5 36 8 +Ethernet144 184,185,186,187 etp37 37 Ext 400000 Eth144 5 37 8 +Ethernet148 188,189,190,191 etp38 38 Ext 400000 Eth148 5 38 8 +Ethernet152 176,177,178,179 etp39 39 Ext 400000 Eth152 5 39 8 +Ethernet156 180,181,182,183 etp40 40 Ext 400000 Eth156 5 40 8 +Ethernet160 248,249,250,251 etp41 41 Ext 400000 Eth160 7 41 8 +Ethernet164 252,253,254,255 etp42 42 Ext 400000 Eth164 7 42 8 +Ethernet168 240,241,242,243 etp43 43 Ext 400000 Eth168 7 43 8 +Ethernet172 244,245,246,247 etp44 44 Ext 400000 Eth172 7 44 8 +Ethernet176 232,233,234,235 etp45 45 Ext 400000 Eth176 7 45 8 +Ethernet180 236,237,238,239 etp46 46 Ext 400000 Eth180 7 46 8 +Ethernet184 224,225,226,227 etp47 47 Ext 400000 Eth184 7 47 8 +Ethernet188 228,229,230,231 etp48 48 Ext 400000 Eth188 7 48 8 +Ethernet192 210,211,208,209 etp49 49 Ext 400000 Eth192 6 49 8 +Ethernet196 212,213,214,215 etp50 50 Ext 400000 Eth196 6 50 8 +Ethernet200 200,201,202,203 etp51 51 Ext 400000 Eth200 6 51 8 +Ethernet204 206,207,204,205 etp52 52 Ext 400000 Eth204 6 52 8 +Ethernet208 219,218,217,216 etp53 53 Ext 400000 Eth208 6 53 8 +Ethernet212 221,220,223,222 etp54 54 Ext 400000 Eth212 6 54 8 +Ethernet216 192,193,194,195 etp55 55 Ext 400000 Eth216 6 55 8 +Ethernet220 198,199,196,197 etp56 56 Ext 400000 Eth220 6 56 8 +Ethernet224 154,155,152,153 etp57 57 Ext 400000 Eth224 4 57 8 +Ethernet228 156,157,158,159 etp58 58 Ext 400000 Eth228 4 58 8 +Ethernet232 144,145,146,147 etp59 59 Ext 400000 Eth232 4 59 8 +Ethernet236 150,151,148,149 etp60 60 Ext 400000 Eth236 4 60 8 +Ethernet240 139,138,137,136 etp61 61 Ext 400000 Eth240 4 61 8 +Ethernet244 141,140,143,142 etp62 62 Ext 400000 Eth244 4 62 8 +Ethernet248 128,129,130,131 etp63 63 Ext 400000 Eth248 4 63 8 +Ethernet252 134,135,132,133 etp64 64 Ext 400000 Eth252 4 64 8 Ethernet-Rec0 280 Recirc0 65 Rec 800000 Rcy0 0 65 8 diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/buffers_defaults_t2.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/buffers_defaults_t2.j2 index 82b04ee679..1ddda381b8 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/buffers_defaults_t2.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/buffers_defaults_t2.j2 @@ -6,8 +6,8 @@ 'torrouter_server' : '300m', 'leafrouter_torrouter' : '300m', 'spinerouter_leafrouter' : '2000m', - 'upperspinerouter_spinerouter' : '50m', - 'upperspinerouter_lowerspinerouter' : '50m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', 'regionalhub_upperspinerouter': '120000m', 'aznghub_upperspinerouter' : '120000m', 'regionalhub_spinerouter': '120000m', @@ -28,7 +28,7 @@ "size": "56441610000", "type": "both", "mode": "dynamic", - "xoff": "2822080500" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/pg_profile_lookup.ini b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/pg_profile_lookup.ini index 3c93a65abb..351a33c4a0 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/pg_profile_lookup.ini +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/BALANCED/pg_profile_lookup.ini @@ -1,20 +1,19 @@ # PG lossless profiles. -# speed cable size xon xoff threshold xon_offset -25000 5m 18796 0 612140 0 3556 -25000 40m 18796 0 612140 0 3556 -25000 300m 18796 0 612140 0 3556 -100000 5m 18796 0 612140 0 3556 -100000 40m 18796 0 612140 0 3556 -100000 300m 18796 0 612140 0 3556 -200000 5m 18796 0 612140 0 3556 -200000 40m 18796 0 612140 0 3556 -200000 300m 18796 0 612140 0 3556 -400000 5m 18796 0 612140 0 3556 -400000 40m 18796 0 612140 0 3556 -400000 50m 18796 0 612140 0 3556 -400000 300m 18796 0 612140 0 3556 -400000 2000m 18796 0 612140 0 3556 -400000 120000m 18796 0 612140 0 3556 -800000 5m 18796 0 612140 0 3556 -800000 40m 18796 0 612140 0 3556 -800000 300m 18796 0 612140 0 3556 +# speed cable size xon xoff threshold xon_offset +100000 30m 0 0 183263 -6 363506 +100000 50m 0 0 185802 -6 363506 +100000 100m 0 0 192149 -6 363506 +100000 300m 0 0 217535 -6 363506 +100000 2000m 0 0 436032 -6 363506 +100000 120000m 0 0 15739154 -6 363506 +400000 30m 0 0 514553 -6 1454025 +400000 50m 0 0 524707 -6 1454025 +400000 100m 0 0 550094 -6 1454025 +400000 300m 0 0 651640 -6 1454025 +400000 2000m 0 0 1514785 -6 1454025 +400000 120000m 0 0 62653744 -6 1454025 +800000 30m 0 0 244000 -6 1454025 +800000 50m 0 0 244000 -6 1454025 +800000 300m 0 0 564000 -6 1454025 +800000 2000m 0 0 2736000 -6 1454025 +800000 120000m 0 0 153440000 -6 1454025 diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/buffers_defaults_t2.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/buffers_defaults_t2.j2 index 463d5b1bb5..e3dffc3a1e 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/buffers_defaults_t2.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/buffers_defaults_t2.j2 @@ -2,6 +2,19 @@ {%- include 'buffer_ports.j2' %} +{%- set ports2cable = { + 'torrouter_server' : '300m', + 'leafrouter_torrouter' : '300m', + 'spinerouter_leafrouter' : '2000m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', + 'regionalhub_upperspinerouter': '120000m', + 'aznghub_upperspinerouter' : '120000m', + 'regionalhub_spinerouter': '120000m', + 'aznghub_spinerouter' : '120000m' + } +-%} + {%- macro generate_qos_bypass_port_list(PORT_QOS_BYPASS) %} {# Generate list of ports #} {%- for port_idx in range(256, 261, 4) %} @@ -14,7 +27,8 @@ "ingress_pool": { "size": "56441610000", "type": "both", - "mode": "dynamic" + "mode": "dynamic", + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/pg_profile_lookup.ini b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/pg_profile_lookup.ini new file mode 100644 index 0000000000..351a33c4a0 --- /dev/null +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O32-C32/pg_profile_lookup.ini @@ -0,0 +1,19 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset +100000 30m 0 0 183263 -6 363506 +100000 50m 0 0 185802 -6 363506 +100000 100m 0 0 192149 -6 363506 +100000 300m 0 0 217535 -6 363506 +100000 2000m 0 0 436032 -6 363506 +100000 120000m 0 0 15739154 -6 363506 +400000 30m 0 0 514553 -6 1454025 +400000 50m 0 0 524707 -6 1454025 +400000 100m 0 0 550094 -6 1454025 +400000 300m 0 0 651640 -6 1454025 +400000 2000m 0 0 1514785 -6 1454025 +400000 120000m 0 0 62653744 -6 1454025 +800000 30m 0 0 244000 -6 1454025 +800000 50m 0 0 244000 -6 1454025 +800000 300m 0 0 564000 -6 1454025 +800000 2000m 0 0 2736000 -6 1454025 +800000 120000m 0 0 153440000 -6 1454025 diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t0.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t0.j2 index e59e13a92a..ba9e6436ec 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t0.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t0.j2 @@ -6,8 +6,8 @@ 'torrouter_server' : '300m', 'leafrouter_torrouter' : '300m', 'spinerouter_leafrouter' : '2000m', - 'upperspinerouter_spinerouter' : '50m', - 'upperspinerouter_lowerspinerouter' : '50m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', 'regionalhub_upperspinerouter': '120000m', 'aznghub_upperspinerouter' : '120000m', 'regionalhub_spinerouter': '120000m', @@ -28,7 +28,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t2.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t2.j2 index 015eec11ee..27eb97714d 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t2.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/buffers_defaults_t2.j2 @@ -6,8 +6,8 @@ 'torrouter_server' : '300m', 'leafrouter_torrouter' : '300m', 'spinerouter_leafrouter' : '2000m', - 'upperspinerouter_spinerouter' : '50m', - 'upperspinerouter_lowerspinerouter' : '50m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', 'regionalhub_upperspinerouter': '120000m', 'aznghub_upperspinerouter' : '120000m', 'regionalhub_spinerouter': '120000m', @@ -33,7 +33,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/pg_profile_lookup.ini b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/pg_profile_lookup.ini index a3ca44ea6f..351a33c4a0 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/pg_profile_lookup.ini +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/BALANCED/pg_profile_lookup.ini @@ -1,13 +1,18 @@ # PG lossless profiles. # speed cable size xon xoff threshold xon_offset -100000 50m 0 0 56000 -6 363506 -100000 300m 0 0 96000 -6 363506 -100000 2000m 0 0 368000 -6 363506 -100000 120000m 0 0 19204000 -6 363506 -400000 50m 0 0 136000 -6 1454025 -400000 300m 0 0 296000 -6 1454025 -400000 2000m 0 0 1384000 -6 1454025 -400000 120000m 0 0 82837504 -6 1454025 +100000 30m 0 0 183263 -6 363506 +100000 50m 0 0 185802 -6 363506 +100000 100m 0 0 192149 -6 363506 +100000 300m 0 0 217535 -6 363506 +100000 2000m 0 0 436032 -6 363506 +100000 120000m 0 0 15739154 -6 363506 +400000 30m 0 0 514553 -6 1454025 +400000 50m 0 0 524707 -6 1454025 +400000 100m 0 0 550094 -6 1454025 +400000 300m 0 0 651640 -6 1454025 +400000 2000m 0 0 1514785 -6 1454025 +400000 120000m 0 0 62653744 -6 1454025 +800000 30m 0 0 244000 -6 1454025 800000 50m 0 0 244000 -6 1454025 800000 300m 0 0 564000 -6 1454025 800000 2000m 0 0 2736000 -6 1454025 diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t0.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t0.j2 index e59e13a92a..ba9e6436ec 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t0.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t0.j2 @@ -6,8 +6,8 @@ 'torrouter_server' : '300m', 'leafrouter_torrouter' : '300m', 'spinerouter_leafrouter' : '2000m', - 'upperspinerouter_spinerouter' : '50m', - 'upperspinerouter_lowerspinerouter' : '50m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', 'regionalhub_upperspinerouter': '120000m', 'aznghub_upperspinerouter' : '120000m', 'regionalhub_spinerouter': '120000m', @@ -28,7 +28,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t2.j2 b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t2.j2 index 015eec11ee..27eb97714d 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t2.j2 +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/buffers_defaults_t2.j2 @@ -6,8 +6,8 @@ 'torrouter_server' : '300m', 'leafrouter_torrouter' : '300m', 'spinerouter_leafrouter' : '2000m', - 'upperspinerouter_spinerouter' : '50m', - 'upperspinerouter_lowerspinerouter' : '50m', + 'upperspinerouter_spinerouter' : '30m', + 'upperspinerouter_lowerspinerouter' : '30m', 'regionalhub_upperspinerouter': '120000m', 'aznghub_upperspinerouter' : '120000m', 'regionalhub_spinerouter': '120000m', @@ -33,7 +33,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/pg_profile_lookup.ini b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/pg_profile_lookup.ini index a3ca44ea6f..351a33c4a0 100644 --- a/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/pg_profile_lookup.ini +++ b/device/nexthop/x86_64-nexthop_5010-r0/NH-5010-F-O64/pg_profile_lookup.ini @@ -1,13 +1,18 @@ # PG lossless profiles. # speed cable size xon xoff threshold xon_offset -100000 50m 0 0 56000 -6 363506 -100000 300m 0 0 96000 -6 363506 -100000 2000m 0 0 368000 -6 363506 -100000 120000m 0 0 19204000 -6 363506 -400000 50m 0 0 136000 -6 1454025 -400000 300m 0 0 296000 -6 1454025 -400000 2000m 0 0 1384000 -6 1454025 -400000 120000m 0 0 82837504 -6 1454025 +100000 30m 0 0 183263 -6 363506 +100000 50m 0 0 185802 -6 363506 +100000 100m 0 0 192149 -6 363506 +100000 300m 0 0 217535 -6 363506 +100000 2000m 0 0 436032 -6 363506 +100000 120000m 0 0 15739154 -6 363506 +400000 30m 0 0 514553 -6 1454025 +400000 50m 0 0 524707 -6 1454025 +400000 100m 0 0 550094 -6 1454025 +400000 300m 0 0 651640 -6 1454025 +400000 2000m 0 0 1514785 -6 1454025 +400000 120000m 0 0 62653744 -6 1454025 +800000 30m 0 0 244000 -6 1454025 800000 50m 0 0 244000 -6 1454025 800000 300m 0 0 564000 -6 1454025 800000 2000m 0 0 2736000 -6 1454025 diff --git a/dockers/docker-bmp-watchdog/Dockerfile.j2 b/dockers/docker-bmp-watchdog/Dockerfile.j2 index 8b1df10fe6..cfe1b6f2d8 100644 --- a/dockers/docker-bmp-watchdog/Dockerfile.j2 +++ b/dockers/docker-bmp-watchdog/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files, rsync_from_builder_stage %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS builder diff --git a/dockers/docker-dhcp-relay/cli-plugin-tests/test_dhcpv4_relay.py b/dockers/docker-dhcp-relay/cli-plugin-tests/test_dhcpv4_relay.py index 3d0b4d043b..329b71bcad 100644 --- a/dockers/docker-dhcp-relay/cli-plugin-tests/test_dhcpv4_relay.py +++ b/dockers/docker-dhcp-relay/cli-plugin-tests/test_dhcpv4_relay.py @@ -494,7 +494,8 @@ def test_config_dhcpv4_relay_agent_relay_mode(self, mock_cfgdb): agent_relay_modes = [ "discard", "append", - "replace" + "replace", + "forward" ] for add_mode in agent_relay_modes: diff --git a/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py b/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py index 0c9cdd5f93..ef889beb58 100644 --- a/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py @@ -223,7 +223,7 @@ def validate_source_interface(vlan_name, source_interface, db): @click.option("--vrf-selection", required=False, type=click.Choice(["enable", "disable"]), help="VRF selection flag for DHCPv4 relay") @click.option("--server-id-override", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable server ID override for DHCPv4 relay") @click.option("--server-vrf", required=False, help="Server VRF name for DHCPv4 relay") -@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace"]), +@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace", "forward"]), help="Set agent relay mode for DHCPv4 relay") @click.option("--max-hop-count", required=False, type=int, help="Maximum hop count for DHCPv4 relay") @click.argument("vlan_name", metavar="", required=True) @@ -318,7 +318,7 @@ def update_dhcpv4_relay(db, vlan_name, dhcpv4_servers, source_interface, link_se @click.option("--vrf-selection", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable VRF selection for DHCPv4 relay") @click.option("--server-id-override", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable server ID override for DHCPv4 relay") @click.option("--server-vrf", required=False, help="Server VRF name for DHCPv4 relay") -@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace"]), +@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace", "forward"]), help="Set agent relay mode for DHCPv4 relay") @click.option("--max-hop-count", required=False, type=int, help="Maximum hop count for DHCPv4 relay") @click.argument("vlan_name", metavar="", required=True) @@ -518,7 +518,7 @@ def dhcp_relay_ipv4_helper(): @click.option("--vrf-selection", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable VRF selection for DHCPv4 relay") @click.option("--server-id-override", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable server ID override for DHCPv4 relay") @click.option("--server-vrf", required=False, help="Server VRF name for DHCPv4 relay") -@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace"]), +@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace", "forward"]), help="Set agent relay mode for DHCPv4 relay") @click.option("--max-hop-count", required=False, type=int, help="Maximum hop count for DHCPv4 relay") @clicommon.pass_db @@ -545,7 +545,7 @@ def add_dhcp_relay_ipv4_helper(db, vid, dhcp_relay_helpers, source_interface, li @click.option("--vrf-selection", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable VRF selection for DHCPv4 relay") @click.option("--server-id-override", required=False, type=click.Choice(["enable", "disable"]), help="Enable/Disable server ID override for DHCPv4 relay") @click.option("--server-vrf", required=False, help="Server VRF name for DHCPv4 relay") -@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace"]), +@click.option("--agent-relay-mode", required=False, type=click.Choice(["discard", "append", "replace", "forward"]), help="Set agent relay mode for DHCPv4 relay") @click.option("--max-hop-count", required=False, type=int, help="Maximum hop count for DHCPv4 relay") @clicommon.pass_db diff --git a/dockers/docker-pde/Dockerfile.j2 b/dockers/docker-pde/Dockerfile.j2 index bdfe3e238f..3129aa2874 100644 --- a/dockers/docker-pde/Dockerfile.j2 +++ b/dockers/docker-pde/Dockerfile.j2 @@ -1,4 +1,4 @@ -FROM docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +FROM docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} ARG docker_container_name ENV PYTHONPATH=/usr/share/sonic/platform @@ -12,16 +12,17 @@ ENV DEBIAN_FRONTEND=noninteractive COPY ["files/03_stretch_af.list", "/etc/apt/sources.list.d/"] {%- endif %} -# Update apt's cache of available packages -RUN apt-get update && apt-get install -y ipmitool telnet busybox kmod libpcap-dev +# Update apt's cache of available packages - Added --no-install-recommends to avoid systemd/udev bloat +RUN apt-get update && apt-get install -y --no-install-recommends ipmitool telnet busybox kmod libpcap-dev # Packages for benchmark tool - nench.sh -RUN apt-get install -y bzip2 curl ioping openssl bc sysstat +RUN apt-get install -y --no-install-recommends bzip2 curl ioping openssl bc sysstat # Packages for PDDF -RUN apt-get install -y python3-jsonschema i2c-tools +RUN apt-get install -y --no-install-recommends python3-jsonschema i2c-tools -RUN pip3 install pytest pexpect +# Use --break-system-packages for Trixie environment +RUN pip3 install --break-system-packages pytest pexpect {% if docker_pde_debs.strip() -%} # Copy locally-built Debian package dependencies @@ -61,8 +62,8 @@ python-wheels/{{ whl }}{{' '}} # Install locally-built Python wheel dependencies -RUN pip3 install \ - +RUN apt-get purge -y python3-jsonschema && \ + pip3 install --break-system-packages \ {% for whl in docker_pde_whls.split(' ') -%} /python-wheels/{{ whl }}{{' '}} diff --git a/dockers/docker-restapi-sidecar/cli-plugin-tests/test_systemd_stub.py b/dockers/docker-restapi-sidecar/cli-plugin-tests/test_systemd_stub.py index 0861c6b905..ccdce3cc56 100644 --- a/dockers/docker-restapi-sidecar/cli-plugin-tests/test_systemd_stub.py +++ b/dockers/docker-restapi-sidecar/cli-plugin-tests/test_systemd_stub.py @@ -1,6 +1,7 @@ # tests/test_systemd_stub.py import sys import os +import time import types import importlib @@ -900,3 +901,74 @@ def test_date_extract_pattern_extracts_correctly(ss): # Should not match match = systemd_stub._DATE_EXTRACT_PATTERN.search("SONiC.master.123456-abcdef12") assert not match + + +# ─────────────────────────── Tests for POST_COPY_ACTIONS docker rm --force ─────────────────────────── + +def test_post_copy_actions_use_docker_rm_force(ss): + """POST_COPY_ACTIONS for restapi.sh should use 'docker rm --force' instead of plain 'docker rm'.""" + ss_mod, *_ = ss + # Re-import to get the real POST_COPY_ACTIONS (fixture clears them) + if "systemd_stub" in sys.modules: + del sys.modules["systemd_stub"] + ss_fresh = importlib.import_module("systemd_stub") + + actions = ss_fresh.POST_COPY_ACTIONS["/usr/bin/restapi.sh"] + # Should have docker stop, docker rm --force, daemon-reload, restart + assert ["sudo", "docker", "stop", "restapi"] in actions + assert ["sudo", "docker", "rm", "--force", "restapi"] in actions + # Old plain 'docker rm' should NOT be present + assert ["sudo", "docker", "rm", "restapi"] not in actions + + +# ─────────────────────────── Tests for sync ordering (k8s_pod_control before restapi.sh) ─────────────── + +def test_sync_order_k8s_pod_control_before_restapi(ss): + """k8s_pod_control.sh must be synced before restapi.sh to avoid 'No such file' errors.""" + ss_mod, container_fs, host_fs, commands, config_db = ss + + container_fs["/usr/share/sonic/systemd_scripts/restapi.sh"] = b"NEW-RESTAPI" + container_fs["/usr/share/sonic/systemd_scripts/container_checker_202311"] = b"NEW-CHECKER" + container_fs["/usr/share/sonic/scripts/k8s_pod_control.sh"] = b"NEW-K8S" + + host_fs["/usr/bin/restapi.sh"] = b"OLD" + host_fs["/bin/container_checker"] = b"OLD" + host_fs["/usr/share/sonic/scripts/docker-restapi-sidecar/k8s_pod_control.sh"] = b"OLD" + + ok = ss_mod.ensure_sync() + assert ok is True + + # Extract the order of file writes by looking at /bin/mv commands (atomic write pattern) + mv_dsts = [args[3] for _, args in commands if args[:1] == ("/bin/mv",) and len(args) == 4] + # k8s_pod_control.sh dest must appear before restapi.sh dest + k8s_dst = "/usr/share/sonic/scripts/docker-restapi-sidecar/k8s_pod_control.sh" + restapi_dst = "/usr/bin/restapi.sh" + if k8s_dst in mv_dsts and restapi_dst in mv_dsts: + assert mv_dsts.index(k8s_dst) < mv_dsts.index(restapi_dst), \ + f"k8s_pod_control.sh must be synced before restapi.sh, but order was: {mv_dsts}" + + +# ─────────────────────────── Tests for main() jitter ─────────────────────────── + +def test_main_loop_uses_jitter(ss, monkeypatch): + """The sync loop sleep should include jitter (interval ± 10%).""" + ss_mod, container_fs, host_fs, commands, config_db = ss + + sleep_values = [] + original_sleep = time.sleep + + def mock_sleep(secs): + sleep_values.append(secs) + raise KeyboardInterrupt # break out of loop after first sleep + + monkeypatch.setattr(time, "sleep", mock_sleep) + monkeypatch.setattr(ss_mod, "ensure_sync", lambda: True) + monkeypatch.setattr(sys, "argv", ["systemd_stub.py", "--interval", "100"]) + + # main() will do initial sync, then enter loop, sleep with jitter, then KeyboardInterrupt + with pytest.raises(KeyboardInterrupt): + ss_mod.main() + + assert len(sleep_values) == 1 + # With 10% jitter on interval=100, sleep should be in [90, 110] + assert 90 <= sleep_values[0] <= 110, f"Sleep value {sleep_values[0]} outside jitter range [90, 110]" diff --git a/dockers/docker-restapi-sidecar/systemd_stub.py b/dockers/docker-restapi-sidecar/systemd_stub.py index 96c6d34de0..2de3779dbf 100644 --- a/dockers/docker-restapi-sidecar/systemd_stub.py +++ b/dockers/docker-restapi-sidecar/systemd_stub.py @@ -2,6 +2,7 @@ from __future__ import annotations import os +import random import re import subprocess import time @@ -12,7 +13,7 @@ from sonic_py_common.sidecar_common import ( get_bool_env_var, logger, SyncItem, run_nsenter, read_file_bytes_local, host_read_bytes, host_write_atomic, - sync_items, SYNC_INTERVAL_S + sync_items, cleanup_native_container, SYNC_INTERVAL_S ) # ───────────── restapi.service paths ───────────── @@ -97,7 +98,7 @@ def _get_branch_name() -> str: POST_COPY_ACTIONS = { "/usr/bin/restapi.sh": [ ["sudo", "docker", "stop", "restapi"], - ["sudo", "docker", "rm", "restapi"], + ["sudo", "docker", "rm", "--force", "restapi"], ["sudo", "systemctl", "daemon-reload"], ["sudo", "systemctl", "restart", "restapi"], ], @@ -202,6 +203,7 @@ def _cleanup_stale_service_unit() -> None: def ensure_sync() -> bool: _cleanup_stale_service_unit() + cleanup_native_container("restapi", IS_V1_ENABLED) # Evaluate branch and source paths each time to allow retry on runtime failures detected_branch = _get_branch_name() @@ -217,10 +219,14 @@ def ensure_sync() -> bool: container_checker_src = f"/usr/share/sonic/systemd_scripts/container_checker_{branch_name}" # Construct SYNC_ITEMS with evaluated paths + # k8s_pod_control.sh must be synced before restapi.sh because the new + # restapi.sh is a thin wrapper that exec's k8s_pod_control.sh. If + # restapi.sh is synced first its post-copy action (systemctl restart + # restapi) would fail with "No such file or directory". sync_items_list: List[SyncItem] = [ + SyncItem("/usr/share/sonic/scripts/k8s_pod_control.sh", "/usr/share/sonic/scripts/docker-restapi-sidecar/k8s_pod_control.sh", mode=0o755), SyncItem(restapi_src, "/usr/bin/restapi.sh", mode=0o755), SyncItem(container_checker_src, "/bin/container_checker", mode=0o755), - SyncItem("/usr/share/sonic/scripts/k8s_pod_control.sh", "/usr/share/sonic/scripts/docker-restapi-sidecar/k8s_pod_control.sh", mode=0o755), ] return sync_items(sync_items_list, POST_COPY_ACTIONS) @@ -245,6 +251,7 @@ def parse_args() -> argparse.Namespace: def main() -> int: args = parse_args() + jitter_pct = 0.1 # ±10% jitter applied to sync loop interval if args.no_post_actions: POST_COPY_ACTIONS.clear() logger.log_info("Post-copy host actions DISABLED for this run") @@ -262,7 +269,8 @@ def main() -> int: return 0 if ok else 1 while True: try: - time.sleep(args.interval) + jitter = args.interval * random.uniform(-jitter_pct, jitter_pct) + time.sleep(args.interval + jitter) ok = ensure_sync() if not ok: logger.log_error("Sync failed. Will retry in next iteration.") diff --git a/dockers/docker-sonic-otel/Dockerfile.j2 b/dockers/docker-sonic-otel/Dockerfile.j2 index e02cd17bd1..e8d1fbae5c 100644 --- a/dockers/docker-sonic-otel/Dockerfile.j2 +++ b/dockers/docker-sonic-otel/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files, rsync_from_builder_stage %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/dockers/docker-sysmgr/Dockerfile.j2 b/dockers/docker-sysmgr/Dockerfile.j2 index 856881ed4a..931dc23e5e 100644 --- a/dockers/docker-sysmgr/Dockerfile.j2 +++ b/dockers/docker-sysmgr/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files, rsync_from_builder_stage %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/dockers/docker-telemetry-sidecar/Dockerfile.j2 b/dockers/docker-telemetry-sidecar/Dockerfile.j2 index 3d69590b91..759c55e931 100644 --- a/dockers/docker-telemetry-sidecar/Dockerfile.j2 +++ b/dockers/docker-telemetry-sidecar/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files, rsync_from_builder_stage %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/platform/broadcom/docker-pde.mk b/platform/broadcom/docker-pde.mk index 476b2e09e1..7c76ef76a0 100644 --- a/platform/broadcom/docker-pde.mk +++ b/platform/broadcom/docker-pde.mk @@ -16,14 +16,14 @@ ifeq ($(PDDF_SUPPORT), y) $(DOCKER_PDE)_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY3) endif $(DOCKER_PDE)_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY3) -$(DOCKER_PDE)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) -$(DOCKER_PDE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) -$(DOCKER_PDE)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BOOKWORM) +$(DOCKER_PDE)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) +$(DOCKER_PDE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) +$(DOCKER_PDE)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_TRIXIE) SONIC_DOCKER_IMAGES += $(DOCKER_PDE) -SONIC_BOOKWORM_DOCKERS += $(DOCKER_PDE) +SONIC_TRIXIE_DOCKERS += $(DOCKER_PDE) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_PDE) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_PDE_DBG) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_PDE_DBG) SONIC_DOCKER_DBG_IMAGES += $(DOCKER_PDE_DBG) SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_PDE_DBG) diff --git a/platform/broadcom/docker-saiserver-brcm.mk b/platform/broadcom/docker-saiserver-brcm.mk index 19f4dd75fd..13a2e1fecb 100644 --- a/platform/broadcom/docker-saiserver-brcm.mk +++ b/platform/broadcom/docker-saiserver-brcm.mk @@ -11,9 +11,9 @@ $(SYNCD_INIT_COMMON_SCRIPT)_PATH = $(SRC_PATH)/sonic-sairedis/syncd/scripts SONIC_COPY_FILES += $(SYNCD_INIT_COMMON_SCRIPT) $(DOCKER_SAISERVER_BRCM)_FILES += $(SYNCD_INIT_COMMON_SCRIPT) -$(DOCKER_SAISERVER_BRCM)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) +$(DOCKER_SAISERVER_BRCM)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) SONIC_DOCKER_IMAGES += $(DOCKER_SAISERVER_BRCM) -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SAISERVER_BRCM) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SAISERVER_BRCM) #Support two versions of saiserver $(DOCKER_SAISERVER_BRCM)_CONTAINER_NAME = saiserver$(SAITHRIFT_VER) diff --git a/platform/broadcom/docker-saiserver-brcm/Dockerfile.j2 b/platform/broadcom/docker-saiserver-brcm/Dockerfile.j2 index 474278b224..f2b61b1eb9 100644 --- a/platform/broadcom/docker-saiserver-brcm/Dockerfile.j2 +++ b/platform/broadcom/docker-saiserver-brcm/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages %} -FROM docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +FROM docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} ARG docker_container_name diff --git a/platform/broadcom/docker-syncd-brcm-dnx-rpc.mk b/platform/broadcom/docker-syncd-brcm-dnx-rpc.mk index 7addfaa280..929f3bc6a5 100644 --- a/platform/broadcom/docker-syncd-brcm-dnx-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-dnx-rpc.mk @@ -30,4 +30,4 @@ $(DOCKER_SYNCD_BRCM_DNX_RPC)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_BRCM_DNX_RPC)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh $(DOCKER_SYNCD_BRCM_DNX_RPC)_MACHINE = broadcom-dnx -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYNCD_BRCM_DNX_RPC) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYNCD_BRCM_DNX_RPC) diff --git a/platform/broadcom/docker-syncd-brcm-dnx-rpc/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm-dnx-rpc/Dockerfile.j2 index ca46722a62..53bbb43a2f 100644 --- a/platform/broadcom/docker-syncd-brcm-dnx-rpc/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm-dnx-rpc/Dockerfile.j2 @@ -22,7 +22,7 @@ RUN apt-get update \ wget \ cmake \ libnanomsg-dev \ - libthrift-0.17.0 + libthrift-0.19.0t64 {% if docker_syncd_brcm_dnx_rpc_debs.strip() -%} # Copy locally-built Debian package dependencies diff --git a/platform/broadcom/docker-syncd-brcm-dnx.mk b/platform/broadcom/docker-syncd-brcm-dnx.mk index d88d19372f..354fb9e89d 100644 --- a/platform/broadcom/docker-syncd-brcm-dnx.mk +++ b/platform/broadcom/docker-syncd-brcm-dnx.mk @@ -6,9 +6,9 @@ DOCKER_SYNCD_DNX_PLATFORM_CODE = brcm-dnx $(DOCKER_SYNCD_DNX_BASE)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_DNX_PLATFORM_CODE) -$(DOCKER_SYNCD_DNX_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) -$(DOCKER_SYNCD_DNX_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) -$(DOCKER_SYNCD_DNX_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) +$(DOCKER_SYNCD_DNX_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) +$(DOCKER_SYNCD_DNX_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) +$(DOCKER_SYNCD_DNX_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_DNX_BASE) ifneq ($(ENABLE_SYNCD_RPC),y) @@ -46,5 +46,5 @@ $(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh $(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcm_common:/usr/bin/bcm_common -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYNCD_DNX_BASE) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_SYNCD_DNX_BASE_DBG) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYNCD_DNX_BASE) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_SYNCD_DNX_BASE_DBG) diff --git a/platform/broadcom/docker-syncd-brcm-dnx/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm-dnx/Dockerfile.j2 index dd5818f0a5..d82f030b00 100755 --- a/platform/broadcom/docker-syncd-brcm-dnx/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm-dnx/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/platform/broadcom/docker-syncd-brcm-legacy-th-rpc.mk b/platform/broadcom/docker-syncd-brcm-legacy-th-rpc.mk index fb7680abd2..bbbcb1f5ee 100644 --- a/platform/broadcom/docker-syncd-brcm-legacy-th-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-legacy-th-rpc.mk @@ -29,4 +29,4 @@ $(DOCKER_SYNCD_BRCM_LEGACY_TH_RPC)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_BRCM_LEGACY_TH_RPC)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh $(DOCKER_SYNCD_BRCM_LEGACY_TH_RPC)_MACHINE = broadcom-legacy-th -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYNCD_BRCM_LEGACY_TH_RPC) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYNCD_BRCM_LEGACY_TH_RPC) diff --git a/platform/broadcom/docker-syncd-brcm-legacy-th.mk b/platform/broadcom/docker-syncd-brcm-legacy-th.mk index f95ddea65f..054e48f790 100644 --- a/platform/broadcom/docker-syncd-brcm-legacy-th.mk +++ b/platform/broadcom/docker-syncd-brcm-legacy-th.mk @@ -6,9 +6,9 @@ DOCKER_SYNCD_LEGACY_TH_PLATFORM_CODE = brcm-legacy-th $(DOCKER_SYNCD_LEGACY_TH_BASE)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_LEGACY_TH_PLATFORM_CODE) -$(DOCKER_SYNCD_LEGACY_TH_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) -$(DOCKER_SYNCD_LEGACY_TH_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) -$(DOCKER_SYNCD_LEGACY_TH_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) +$(DOCKER_SYNCD_LEGACY_TH_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) +$(DOCKER_SYNCD_LEGACY_TH_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) +$(DOCKER_SYNCD_LEGACY_TH_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_LEGACY_TH_BASE) ifneq ($(ENABLE_SYNCD_RPC),y) @@ -36,7 +36,7 @@ endif $(DOCKER_SYNCD_LEGACY_TH_BASE)_VERSION = 1.0.0 $(DOCKER_SYNCD_LEGACY_TH_BASE)_PACKAGE_NAME = syncd-legacy-th $(DOCKER_SYNCD_LEGACY_TH_BASE)_MACHINE = broadcom-legacy-th -$(DOCKER_SYNCD_LEGACY_TH_BASE)_AFTER = $(DOCKER_SYNCD_DNX_BASE) +$(DOCKER_SYNCD_LEGACY_TH_BASE)_AFTER = $(DOCKER_CONFIG_ENGINE_TRIXIE) $(DOCKER_SYNCD_LEGACY_TH_BASE)_CONTAINER_NAME = syncd $(DOCKER_SYNCD_LEGACY_TH_BASE)_RUN_OPT += --privileged -t @@ -47,5 +47,5 @@ $(DOCKER_SYNCD_LEGACY_TH_BASE)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_LEGACY_TH_BASE)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh $(DOCKER_SYNCD_LEGACY_TH_BASE)_BASE_IMAGE_FILES += bcm_common:/usr/bin/bcm_common -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYNCD_LEGACY_TH_BASE) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_SYNCD_LEGACY_TH_BASE_DBG) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYNCD_LEGACY_TH_BASE) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_SYNCD_LEGACY_TH_BASE_DBG) diff --git a/platform/broadcom/docker-syncd-brcm-legacy-th/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm-legacy-th/Dockerfile.j2 index ca56b6653b..3fb68c70c8 100755 --- a/platform/broadcom/docker-syncd-brcm-legacy-th/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm-legacy-th/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/platform/broadcom/docker-syncd-brcm-rpc.mk b/platform/broadcom/docker-syncd-brcm-rpc.mk index b4d2a90512..75877dc966 100644 --- a/platform/broadcom/docker-syncd-brcm-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-rpc.mk @@ -29,4 +29,4 @@ $(DOCKER_SYNCD_BRCM_RPC)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_BRCM_RPC)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh $(DOCKER_SYNCD_BRCM_RPC)_MACHINE = broadcom -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYNCD_BRCM_RPC) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYNCD_BRCM_RPC) diff --git a/platform/broadcom/docker-syncd-brcm-rpc/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm-rpc/Dockerfile.j2 index faeacc39d6..183be767bb 100644 --- a/platform/broadcom/docker-syncd-brcm-rpc/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm-rpc/Dockerfile.j2 @@ -22,7 +22,7 @@ RUN apt-get update \ wget \ cmake \ libnanomsg-dev \ - libthrift-0.17.0 + libthrift-0.19.0t64 {% if docker_syncd_brcm_rpc_debs.strip() -%} # Copy locally-built Debian package dependencies diff --git a/platform/broadcom/docker-syncd-brcm.mk b/platform/broadcom/docker-syncd-brcm.mk index 29ddb9085a..42862cc870 100644 --- a/platform/broadcom/docker-syncd-brcm.mk +++ b/platform/broadcom/docker-syncd-brcm.mk @@ -1,7 +1,8 @@ # docker image for brcm syncd DOCKER_SYNCD_PLATFORM_CODE = brcm -include $(PLATFORM_PATH)/../template/docker-syncd-bookworm.mk + +include $(PLATFORM_PATH)/../template/docker-syncd-trixie.mk $(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(DOCKER_SYNCD_BASE)_DEPENDS += $(BRCM_XGS_SAI) diff --git a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 index bde3d59fc1..4eafd1366f 100755 --- a/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 +++ b/platform/broadcom/docker-syncd-brcm/Dockerfile.j2 @@ -1,5 +1,5 @@ {% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files %} -ARG BASE=docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} +ARG BASE=docker-config-engine-trixie-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} FROM $BASE AS base diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/dev_monitor.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/dev_monitor.py index e13377b80f..5947763908 100755 --- a/platform/broadcom/sonic-platform-modules-ragile/common/script/dev_monitor.py +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/dev_monitor.py @@ -108,18 +108,20 @@ def getpresentstatus(self, param): return ret def removeDev(self, bus, loc): - cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) if os.path.exists(devpath): - os.system(cmd) + delete_file = "/sys/bus/i2c/devices/i2c-%d/delete_device" % bus + with open(delete_file, 'w') as f: + f.write("0x%02x\n" % loc) def addDev(self, name, bus, loc): if name == "lm75": time.sleep(0.1) - cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) if os.path.exists(devpath) is False: - os.system(cmd) + new_device_file = "/sys/bus/i2c/devices/i2c-%d/new_device" % bus + with open(new_device_file, 'w') as f: + f.write("%s 0x%02x\n" % (name, loc)) def checkattr(self, bus, loc, attr): try: diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/generate_airflow.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/generate_airflow.py index 29d18e7b26..74c12d9e06 100755 --- a/platform/broadcom/sonic-platform-modules-ragile/common/script/generate_airflow.py +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/generate_airflow.py @@ -16,6 +16,7 @@ } ''' import os +import subprocess import syslog import json from platform_config import AIR_FLOW_CONF, AIRFLOW_RESULT_FILE @@ -222,12 +223,11 @@ def generate_airflow(): out_file_dir = os.path.dirname(AIRFLOW_RESULT_FILE) if len(out_file_dir) != 0: - cmd = "mkdir -p %s" % out_file_dir - os.system(cmd) - os.system("sync") + subprocess.call(["mkdir", "-p", out_file_dir]) + subprocess.call(["sync"]) with open(AIRFLOW_RESULT_FILE, "w") as fd: fd.write(ret_json) - os.system("sync") + subprocess.call(["sync"]) if __name__ == '__main__': diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/monitor_fan.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/monitor_fan.py index c84319f3b7..adc9cd1e04 100755 --- a/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/monitor_fan.py +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/monitor_fan.py @@ -2,6 +2,7 @@ # -*- coding: UTF-8 -*- import os +import subprocess import time import logging from logging.handlers import RotatingFileHandler @@ -19,8 +20,8 @@ def _init_logger(): if not os.path.exists(LOG_FILE): - os.system("mkdir -p %s" % os.path.dirname(LOG_FILE)) - os.system("sync") + subprocess.call(["mkdir", "-p", os.path.dirname(LOG_FILE)]) + subprocess.call(["sync"]) handler = RotatingFileHandler(filename=LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=1) formatter = logging.Formatter("%(asctime)s %(levelname)s %(filename)s[%(funcName)s][%(lineno)s]: %(message)s") handler.setFormatter(formatter) diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/tests/test_monitor_fan.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/tests/test_monitor_fan.py new file mode 100644 index 0000000000..1f2abc7f60 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/intelligent_monitor/tests/test_monitor_fan.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +""" +Unit tests for monitor_fan.py +""" + +import os +import sys +import time +import pytest +from unittest.mock import patch, MagicMock, PropertyMock + +# Mock platform-specific imports +sys.modules['plat_hal'] = MagicMock() +sys.modules['plat_hal.interface'] = MagicMock() +sys.modules['plat_hal.baseutil'] = MagicMock() + +import monitor_fan as mf + + +class TestInitLogger: + """Tests for _init_logger()""" + + @patch('monitor_fan.RotatingFileHandler') + @patch('subprocess.call') + @patch('os.path.exists', return_value=False) + def test_creates_log_directory_when_missing(self, mock_exists, mock_call, mock_handler): + logger = mf._init_logger() + mock_call.assert_any_call(["mkdir", "-p", os.path.dirname(mf.LOG_FILE)]) + mock_call.assert_any_call(["sync"]) + assert logger is not None + + @patch('monitor_fan.RotatingFileHandler') + @patch('os.path.exists', return_value=True) + def test_skips_mkdir_when_log_exists(self, mock_exists, mock_handler): + with patch('subprocess.call') as mock_call: + logger = mf._init_logger() + mock_call.assert_not_called() + assert logger is not None + + +class TestFan: + """Tests for Fan class""" + + def setup_method(self): + self.mock_interface = MagicMock() + self.fan = mf.Fan("FAN1", self.mock_interface) + + def test_init(self): + assert self.fan.name == "FAN1" + assert self.fan.pre_present is False + assert self.fan.pre_status is True + assert self.fan.plugin_cnt == 0 + assert self.fan.plugout_cnt == 0 + + def test_fan_dict_update_caches(self): + self.mock_interface.get_fan_info.return_value = {"NAME": "FAN-A", "SN": "123"} + self.fan.fan_dict_update() + self.fan.fan_dict_update() # second call should use cache + self.mock_interface.get_fan_info.assert_called_once() + + def test_fan_dict_update_refreshes_after_interval(self): + self.mock_interface.get_fan_info.return_value = {"NAME": "FAN-A", "SN": "123"} + self.fan.fan_dict_update() + self.fan.update_time = time.time() - 2 # simulate 2 seconds ago + self.fan.fan_dict_update() + assert self.mock_interface.get_fan_info.call_count == 2 + + def test_get_model(self): + self.mock_interface.get_fan_info.return_value = {"NAME": "FAN-MODEL-A", "SN": "123"} + assert self.fan.get_model() == "FAN-MODEL-A" + + def test_get_serial(self): + self.mock_interface.get_fan_info.return_value = {"NAME": "FAN-A", "SN": "SN12345"} + assert self.fan.get_serial() == "SN12345" + + def test_get_presence(self): + self.mock_interface.get_fan_presence.return_value = True + assert self.fan.get_presence() is True + self.mock_interface.get_fan_presence.assert_called_with("FAN1") + + def test_get_rotor_speed_normal(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 8000, "SpeedMax": 10000} + } + assert self.fan.get_rotor_speed("Rotor1") == 80 + + def test_get_rotor_speed_over_100_capped(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 12000, "SpeedMax": 10000} + } + assert self.fan.get_rotor_speed("Rotor1") == 100 + + def test_get_rotor_speed_string_value_returns_zero(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": "N/A", "SpeedMax": 10000} + } + assert self.fan.get_rotor_speed("Rotor1") == 0 + + def test_get_rotor_speed_none_value_returns_zero(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": None, "SpeedMax": 10000} + } + assert self.fan.get_rotor_speed("Rotor1") == 0 + + def test_get_rotor_speed_tolerance_normal(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Tolerance": 25} + } + assert self.fan.get_rotor_speed_tolerance("Rotor1") == 25 + + def test_get_rotor_speed_tolerance_string_returns_default(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Tolerance": "N/A"} + } + assert self.fan.get_rotor_speed_tolerance("Rotor1") == 30 + + def test_get_rotor_speed_tolerance_none_returns_default(self): + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Tolerance": None} + } + assert self.fan.get_rotor_speed_tolerance("Rotor1") == 30 + + def test_get_target_speed(self): + self.mock_interface.get_fan_speed_pwm.return_value = 75 + assert self.fan.get_target_speed() == 75 + + def test_get_status_not_present(self): + self.mock_interface.get_fan_presence.return_value = False + assert self.fan.get_status() is False + + def test_get_status_speed_within_tolerance(self): + self.mock_interface.get_fan_presence.return_value = True + self.mock_interface.get_fan_rotor_number.return_value = 1 + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 7500, "SpeedMax": 10000, "Tolerance": 30} + } + self.mock_interface.get_fan_speed_pwm.return_value = 75 + assert self.fan.get_status() is True + + def test_get_status_speed_too_high(self): + self.mock_interface.get_fan_presence.return_value = True + self.mock_interface.get_fan_rotor_number.return_value = 1 + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 10000, "SpeedMax": 10000, "Tolerance": 10} + } + self.mock_interface.get_fan_speed_pwm.return_value = 50 # target 50%, actual 100% + assert self.fan.get_status() is False + + def test_get_status_speed_too_low(self): + self.mock_interface.get_fan_presence.return_value = True + self.mock_interface.get_fan_rotor_number.return_value = 1 + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 1000, "SpeedMax": 10000, "Tolerance": 10} + } + self.mock_interface.get_fan_speed_pwm.return_value = 80 # target 80%, actual 10% + assert self.fan.get_status() is False + + def test_get_status_multiple_rotors(self): + self.mock_interface.get_fan_presence.return_value = True + self.mock_interface.get_fan_rotor_number.return_value = 2 + self.mock_interface.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 7500, "SpeedMax": 10000, "Tolerance": 30}, + "Rotor2": {"Speed": 7500, "SpeedMax": 10000, "Tolerance": 30}, + } + self.mock_interface.get_fan_speed_pwm.return_value = 75 + assert self.fan.get_status() is True + + def test_get_direction(self): + self.mock_interface.get_fan_info.return_value = {"NAME": "FAN-A", "SN": "123", "AirFlow": "intake"} + assert self.fan.get_direction() == "intake" + + +class TestMonitorFan: + """Tests for MonitorFan class""" + + def setup_method(self): + self.mock_baseutil = MagicMock() + self.mock_baseutil.get_monitor_config.return_value = { + "monitor_fan_para": { + "present_interval": 0.5, + "status_interval": 5, + "present_check_cnt": 3, + "status_check_cnt": 3, + } + } + with patch.object(mf, 'baseutil', self.mock_baseutil), \ + patch.object(mf, 'interface', MagicMock()), \ + patch.object(mf, '_init_logger', return_value=MagicMock()): + self.monitor = mf.MonitorFan() + + def test_debug_init_debug_mode(self): + with patch('os.path.exists', return_value=True): + self.monitor.debug_init() + self.monitor.logger.setLevel.assert_called_with(mf.logging.DEBUG) + + def test_debug_init_info_mode(self): + with patch('os.path.exists', return_value=False): + self.monitor.debug_init() + self.monitor.logger.setLevel.assert_called_with(mf.logging.INFO) + + def test_fan_obj_init(self): + self.monitor.int_case.get_fan_total_number.return_value = 3 + self.monitor.fan_obj_init() + assert len(self.monitor.fan_obj_list) == 3 + assert self.monitor.fan_obj_list[0].name == "FAN1" + assert self.monitor.fan_obj_list[2].name == "FAN3" + + def test_fan_airflow_check_match(self): + fan_obj = MagicMock() + fan_obj.name = "FAN1" + fan_obj.get_direction.return_value = "intake" + self.monitor.int_case.get_device_airflow.return_value = "intake" + + self.monitor.fan_airflow_check(fan_obj) + self.monitor.logger.debug.assert_called() + + def test_fan_airflow_check_mismatch(self): + fan_obj = MagicMock() + fan_obj.name = "FAN1" + fan_obj.get_direction.return_value = "intake" + self.monitor.int_case.get_device_airflow.return_value = "exhaust" + + self.monitor.fan_airflow_check(fan_obj) + self.monitor.logger.error.assert_called() + + def test_fan_plug_in_detected(self): + fan_obj = mf.Fan("FAN1", MagicMock()) + fan_obj.pre_present = False + fan_obj.int_case.get_fan_presence.return_value = True + # Need 3 consecutive detections + for _ in range(3): + self.monitor.fan_plug_in_out_check(fan_obj) + assert fan_obj.pre_present is True + + def test_fan_plug_out_detected(self): + fan_obj = mf.Fan("FAN1", MagicMock()) + fan_obj.pre_present = True + fan_obj.int_case.get_fan_presence.return_value = False + for _ in range(3): + self.monitor.fan_plug_in_out_check(fan_obj) + assert fan_obj.pre_present is False + + def test_fan_plug_in_not_enough_count(self): + fan_obj = mf.Fan("FAN1", MagicMock()) + fan_obj.pre_present = False + fan_obj.int_case.get_fan_presence.return_value = True + self.monitor.fan_plug_in_out_check(fan_obj) # only 1 detection + assert fan_obj.pre_present is False # not yet confirmed + + def test_fan_status_normal_to_error(self): + fan_obj = mf.Fan("FAN1", MagicMock()) + fan_obj.pre_status = True + fan_obj.int_case.get_fan_presence.return_value = True + fan_obj.int_case.get_fan_rotor_number.return_value = 1 + fan_obj.int_case.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 1000, "SpeedMax": 10000, "Tolerance": 10} + } + fan_obj.int_case.get_fan_speed_pwm.return_value = 80 # way off + for _ in range(3): + self.monitor.fan_status_check(fan_obj) + assert fan_obj.pre_status is False + + def test_fan_status_error_to_normal(self): + fan_obj = mf.Fan("FAN1", MagicMock()) + fan_obj.pre_status = False + fan_obj.int_case.get_fan_presence.return_value = True + fan_obj.int_case.get_fan_rotor_number.return_value = 1 + fan_obj.int_case.get_fan_info_rotor.return_value = { + "Rotor1": {"Speed": 7500, "SpeedMax": 10000, "Tolerance": 30} + } + fan_obj.int_case.get_fan_speed_pwm.return_value = 75 + for _ in range(3): + self.monitor.fan_status_check(fan_obj) + assert fan_obj.pre_status is True + + def test_checkFanPresence_iterates_all(self): + fan1 = MagicMock() + fan2 = MagicMock() + self.monitor.fan_obj_list = [fan1, fan2] + with patch.object(self.monitor, 'fan_plug_in_out_check') as mock_check: + self.monitor.checkFanPresence() + assert mock_check.call_count == 2 + + def test_checkFanStatus_iterates_all(self): + fan1 = MagicMock() + fan2 = MagicMock() + self.monitor.fan_obj_list = [fan1, fan2] + with patch.object(self.monitor, 'fan_status_check') as mock_check: + self.monitor.checkFanStatus() + assert mock_check.call_count == 2 diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/platform_driver.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/platform_driver.py index 6d2c6de653..f11ca70777 100755 --- a/platform/broadcom/sonic-platform-modules-ragile/common/script/platform_driver.py +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/platform_driver.py @@ -55,10 +55,11 @@ def check_driver(): def removeDev(bus, loc): - cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) if os.path.exists(devpath): - log_os_system(cmd) + delete_file = "/sys/bus/i2c/devices/i2c-%d/delete_device" % bus + with open(delete_file, 'w') as f: + f.write("0x%02x\n" % loc) def addDev(name, bus, loc): @@ -72,10 +73,11 @@ def addDev(name, bus, loc): if i % 10 == 0: click.echo("%%WB_PLATFORM_DRIVER-INIT: %s not found, wait 0.1 second ! i %d " % (pdevpath, i)) - cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) if os.path.exists(devpath) is False: - os.system(cmd) + new_device_file = "/sys/bus/i2c/devices/i2c-%d/new_device" % bus + with open(new_device_file, 'w') as f: + f.write("%s 0x%02x\n" % (name, loc)) def removeOPTOE(startbus, endbus): diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_dev_monitor.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_dev_monitor.py new file mode 100644 index 0000000000..c8347bdcde --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_dev_monitor.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +""" +Unit tests for dev_monitor.py — focused on removeDev and addDev +""" + +import os +import sys +import pytest +from unittest.mock import patch, mock_open, MagicMock, call + +# Mock platform-specific imports +mock_config = MagicMock() +mock_config.DEV_MONITOR_PARAM = {} +sys.modules['platform_config'] = mock_config +sys.modules['platform_util'] = MagicMock() +sys.modules['click'] = MagicMock() + +import dev_monitor as dm + + +class TestDevMonitorRemoveDev: + """Tests for DevMonitor.removeDev()""" + + def setup_method(self): + + self.monitor = dm.DevMonitor.__new__(dm.DevMonitor) + self.monitor.logger = MagicMock() + + @patch('os.path.exists', return_value=True) + def test_removes_existing_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + self.monitor.removeDev(10, 0x56) + m.assert_called_once_with("/sys/bus/i2c/devices/i2c-10/delete_device", 'w') + m().write.assert_called_once_with("0x56\n") + + @patch('os.path.exists', return_value=False) + def test_skips_nonexistent_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + self.monitor.removeDev(10, 0x56) + m.assert_not_called() + + @patch('os.path.exists', return_value=True) + def test_correct_devpath_format(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + self.monitor.removeDev(5, 0x48) + mock_exists.assert_called_with("/sys/bus/i2c/devices/5-0048") + + +class TestDevMonitorAddDev: + """Tests for DevMonitor.addDev()""" + + def setup_method(self): + + self.monitor = dm.DevMonitor.__new__(dm.DevMonitor) + self.monitor.logger = MagicMock() + + @patch('os.path.exists', return_value=False) + def test_adds_new_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + self.monitor.addDev("tmp75", 10, 0x48) + m.assert_called_once_with("/sys/bus/i2c/devices/i2c-10/new_device", 'w') + m().write.assert_called_once_with("tmp75 0x48\n") + + @patch('os.path.exists', return_value=True) + def test_skips_existing_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + self.monitor.addDev("tmp75", 10, 0x48) + m.assert_not_called() + + @patch('time.sleep') + @patch('os.path.exists', return_value=False) + def test_lm75_sleeps_before_add(self, mock_exists, mock_sleep): + m = mock_open() + with patch("builtins.open", m): + self.monitor.addDev("lm75", 10, 0x48) + mock_sleep.assert_called_once_with(0.1) + + @patch('os.path.exists', return_value=False) + def test_non_lm75_no_sleep(self, mock_exists): + m = mock_open() + with patch("builtins.open", m), \ + patch('time.sleep') as mock_sleep: + self.monitor.addDev("tmp75", 10, 0x48) + mock_sleep.assert_not_called() diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_generate_airflow.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_generate_airflow.py new file mode 100644 index 0000000000..39acf9d749 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_generate_airflow.py @@ -0,0 +1,387 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +""" +Unit tests for generate_airflow.py +""" + +import os +import sys +import json +import pytest +from unittest.mock import patch, mock_open, MagicMock + +# Mock platform-specific imports before importing the module under test +sys.modules['platform_config'] = MagicMock() +sys.modules['platform_util'] = MagicMock() +sys.modules['eepromutil'] = MagicMock() +sys.modules['eepromutil.fru'] = MagicMock() +sys.modules['eepromutil.fantlv'] = MagicMock() + +# Now we can import +import generate_airflow as ga + + +class TestGetBoardAirFlow: + """Tests for get_board_air_flow()""" + + def test_all_zeros_returns_na(self): + with patch.object(ga, 'airflow_error'): + result = ga.get_board_air_flow(0, 0, 0, 0) + assert result == "N/A" + + def test_more_intake_fans_returns_intake(self): + result = ga.get_board_air_flow(3, 1, 0, 0) + assert result == "intake" + + def test_more_exhaust_fans_returns_exhaust(self): + result = ga.get_board_air_flow(1, 3, 0, 0) + assert result == "exhaust" + + def test_equal_fans_more_intake_psus_returns_intake(self): + result = ga.get_board_air_flow(2, 2, 2, 1) + assert result == "intake" + + def test_equal_fans_more_exhaust_psus_returns_exhaust(self): + result = ga.get_board_air_flow(2, 2, 1, 2) + assert result == "exhaust" + + def test_all_equal_returns_intake(self): + result = ga.get_board_air_flow(2, 2, 2, 2) + assert result == "intake" + + def test_only_fans_intake(self): + result = ga.get_board_air_flow(4, 0, 0, 0) + assert result == "intake" + + def test_only_fans_exhaust(self): + result = ga.get_board_air_flow(0, 4, 0, 0) + assert result == "exhaust" + + def test_only_psus_intake(self): + result = ga.get_board_air_flow(0, 0, 2, 0) + assert result == "intake" + + def test_only_psus_exhaust(self): + result = ga.get_board_air_flow(0, 0, 0, 2) + assert result == "exhaust" + + def test_fans_override_psus(self): + result = ga.get_board_air_flow(3, 1, 0, 4) + assert result == "intake" + + +class TestGetModelFru: + """Tests for get_model_fru()""" + + def test_success(self): + device = {"name": "FAN1", "area": "boardInfoArea", "field": "boardPartNumber"} + mock_fru = MagicMock() + mock_area = MagicMock() + mock_area.boardPartNumber = "M1HFAN-I-F" + mock_fru.boardInfoArea = mock_area + + with patch.object(ga, 'ipmifru', return_value=mock_fru): + status, model = ga.get_model_fru(device, b'\x00' * 256) + assert status is True + assert model == "M1HFAN-I-F" + + def test_invalid_area(self): + device = {"name": "FAN1", "area": "nonExistentArea", "field": "boardPartNumber"} + mock_fru = MagicMock() + mock_fru.nonExistentArea = None + + with patch.object(ga, 'ipmifru', return_value=mock_fru): + status, msg = ga.get_model_fru(device, b'\x00' * 256) + assert status is False + assert "area config error" in msg + + def test_invalid_field(self): + device = {"name": "FAN1", "area": "boardInfoArea", "field": "nonExistentField"} + mock_fru = MagicMock() + mock_area = MagicMock(spec=[]) + mock_fru.boardInfoArea = mock_area + + with patch.object(ga, 'ipmifru', return_value=mock_fru): + status, msg = ga.get_model_fru(device, b'\x00' * 256) + assert status is False + assert "get model error" in msg + + def test_exception(self): + device = {"name": "FAN1", "area": "boardInfoArea", "field": "boardPartNumber"} + + with patch.object(ga, 'ipmifru', side_effect=Exception("decode error")): + status, msg = ga.get_model_fru(device, b'\x00' * 256) + assert status is False + assert "decode error" in msg + + +class TestGetModelFantlv: + """Tests for get_model_fantlv()""" + + def test_success(self): + device = {"name": "FAN1", "field": "Model"} + mock_tlv = MagicMock() + mock_tlv.decode.return_value = [{"name": "Model", "value": "FAN-INTAKE-001"}] + + with patch.object(ga, 'fan_tlv', return_value=mock_tlv): + status, model = ga.get_model_fantlv(device, b'\x00' * 256) + assert status is True + assert model == "FAN-INTAKE-001" + + def test_empty_decode(self): + device = {"name": "FAN1", "field": "Model"} + mock_tlv = MagicMock() + mock_tlv.decode.return_value = [] + + with patch.object(ga, 'fan_tlv', return_value=mock_tlv): + status, msg = ga.get_model_fantlv(device, b'\x00' * 256) + assert status is False + assert "decode fantlv eeprom info error" in msg + + def test_field_not_found(self): + device = {"name": "FAN1", "field": "Model"} + mock_tlv = MagicMock() + mock_tlv.decode.return_value = [{"name": "Serial", "value": "123"}] + + with patch.object(ga, 'fan_tlv', return_value=mock_tlv): + status, msg = ga.get_model_fantlv(device, b'\x00' * 256) + assert status is False + assert "not found" in msg + + def test_exception(self): + device = {"name": "FAN1", "field": "Model"} + mock_tlv = MagicMock() + mock_tlv.decode.side_effect = Exception("tlv error") + + with patch.object(ga, 'fan_tlv', return_value=mock_tlv): + status, msg = ga.get_model_fantlv(device, b'\x00' * 256) + assert status is False + assert "tlv error" in msg + + +class TestGetDeviceModele: + """Tests for get_device_modele()""" + + def test_unsupported_e2_type(self): + device = {"name": "FAN1", "e2_type": "unknown"} + status, msg = ga.get_device_modele(device) + assert status is False + assert "unsupport e2_type" in msg + + def test_eeprom_read_failure(self): + device = {"name": "FAN1", "e2_type": "fru", "e2_path": "/dev/fake", "e2_size": 256} + + with patch.object(ga, 'dev_file_read', return_value=(False, "read error")): + status, msg = ga.get_device_modele(device) + assert status is False + assert "eeprom read error" in msg + + def test_fru_type_calls_get_model_fru(self): + device = {"name": "FAN1", "e2_type": "fru", "e2_path": "/dev/fake", "e2_size": 256, + "area": "boardInfoArea", "field": "boardPartNumber"} + + with patch.object(ga, 'dev_file_read', return_value=(True, b'\x00' * 256)), \ + patch.object(ga, 'byteTostr', return_value="eeprom_data"), \ + patch.object(ga, 'get_model_fru', return_value=(True, "MODEL-A")) as mock_fru: + status, model = ga.get_device_modele(device) + assert status is True + assert model == "MODEL-A" + mock_fru.assert_called_once() + + def test_fantlv_type_calls_get_model_fantlv(self): + device = {"name": "FAN1", "e2_type": "fantlv", "e2_path": "/dev/fake", "e2_size": 256, + "field": "Model"} + + with patch.object(ga, 'dev_file_read', return_value=(True, b'\x00' * 256)), \ + patch.object(ga, 'byteTostr', return_value="eeprom_data"), \ + patch.object(ga, 'get_model_fantlv', return_value=(True, "MODEL-B")) as mock_fantlv: + status, model = ga.get_device_modele(device) + assert status is True + assert model == "MODEL-B" + mock_fantlv.assert_called_once() + + def test_default_e2_size(self): + device = {"name": "FAN1", "e2_type": "fru", "e2_path": "/dev/fake", + "area": "boardInfoArea", "field": "boardPartNumber"} + + with patch.object(ga, 'dev_file_read', return_value=(True, b'\x00' * 256)) as mock_read, \ + patch.object(ga, 'byteTostr', return_value="data"), \ + patch.object(ga, 'get_model_fru', return_value=(True, "MODEL")): + ga.get_device_modele(device) + mock_read.assert_called_once_with("/dev/fake", 0, 256) + + +class TestDebugInit: + """Tests for debug_init()""" + + def test_sets_debuglevel_from_file(self): + with patch("builtins.open", mock_open(read_data="3")): + ga.debug_init() + assert ga.debuglevel == 3 + + def test_defaults_to_zero_on_missing_file(self): + with patch("builtins.open", side_effect=FileNotFoundError): + ga.debug_init() + assert ga.debuglevel == 0 + + def test_defaults_to_zero_on_invalid_content(self): + with patch("builtins.open", mock_open(read_data="abc")): + ga.debug_init() + assert ga.debuglevel == 0 + + +class TestGenerateAirflow: + """Tests for generate_airflow()""" + + def setup_method(self): + self.air_flow_conf = { + "fans": [ + {"name": "FAN1", "e2_type": "fru", "e2_path": "/dev/fan1", + "e2_size": 256, "area": "boardInfoArea", "field": "boardPartNumber", + "decode": "fan_airflow"}, + {"name": "FAN2", "e2_type": "fru", "e2_path": "/dev/fan2", + "e2_size": 256, "area": "boardInfoArea", "field": "boardPartNumber", + "decode": "fan_airflow"}, + ], + "psus": [ + {"name": "PSU1", "e2_type": "fru", "e2_path": "/dev/psu1", + "e2_size": 256, "area": "boardInfoArea", "field": "boardPartNumber", + "decode": "psu_airflow"}, + ], + "fan_airflow": { + "intake": ["MODEL-INTAKE"], + "exhaust": ["MODEL-EXHAUST"], + }, + "psu_airflow": { + "intake": ["PSU-INTAKE"], + "exhaust": ["PSU-EXHAUST"], + }, + } + + def test_all_intake(self, tmp_path): + result_file = str(tmp_path / "airflow_result.json") + ga.AIR_FLOW_CONF = self.air_flow_conf + + with patch.object(ga, 'AIRFLOW_RESULT_FILE', result_file), \ + patch.object(ga, 'get_device_modele') as mock_model, \ + patch('subprocess.call') as mock_call: + mock_model.side_effect = [ + (True, "MODEL-INTAKE"), + (True, "MODEL-INTAKE"), + (True, "PSU-INTAKE"), + ] + ga.generate_airflow() + + with open(result_file, 'r') as f: + result = json.load(f) + + assert result["FAN1"]["airflow"] == "intake" + assert result["FAN2"]["airflow"] == "intake" + assert result["PSU1"]["airflow"] == "intake" + assert result["board"] == "intake" + mock_call.assert_any_call(["sync"]) + + def test_mixed_airflow(self, tmp_path): + result_file = str(tmp_path / "airflow_result.json") + ga.AIR_FLOW_CONF = self.air_flow_conf + + with patch.object(ga, 'AIRFLOW_RESULT_FILE', result_file), \ + patch.object(ga, 'get_device_modele') as mock_model, \ + patch('subprocess.call') as mock_call: + mock_model.side_effect = [ + (True, "MODEL-INTAKE"), + (True, "MODEL-EXHAUST"), + (True, "PSU-INTAKE"), + ] + ga.generate_airflow() + + with open(result_file, 'r') as f: + result = json.load(f) + + assert result["FAN1"]["airflow"] == "intake" + assert result["FAN2"]["airflow"] == "exhaust" + assert result["board"] == "intake" + mock_call.assert_any_call(["sync"]) + + def test_fan_eeprom_read_failure(self, tmp_path): + result_file = str(tmp_path / "airflow_result.json") + ga.AIR_FLOW_CONF = self.air_flow_conf + + with patch.object(ga, 'AIRFLOW_RESULT_FILE', result_file), \ + patch.object(ga, 'get_device_modele') as mock_model, \ + patch('subprocess.call'): + mock_model.side_effect = [ + (False, "read error"), + (True, "MODEL-EXHAUST"), + (True, "PSU-EXHAUST"), + ] + ga.generate_airflow() + + with open(result_file, 'r') as f: + result = json.load(f) + + assert result["FAN1"]["model"] == "N/A" + assert result["FAN1"]["airflow"] == "N/A" + assert result["board"] == "exhaust" + + def test_unknown_model(self, tmp_path): + result_file = str(tmp_path / "airflow_result.json") + ga.AIR_FLOW_CONF = self.air_flow_conf + + with patch.object(ga, 'AIRFLOW_RESULT_FILE', result_file), \ + patch.object(ga, 'get_device_modele') as mock_model, \ + patch('subprocess.call'): + mock_model.side_effect = [ + (True, "UNKNOWN-MODEL"), + (True, "UNKNOWN-MODEL"), + (True, "UNKNOWN-MODEL"), + ] + ga.generate_airflow() + + with open(result_file, 'r') as f: + result = json.load(f) + + assert result["FAN1"]["airflow"] == "N/A" + assert result["board"] == "N/A" + + def test_creates_output_directory(self, tmp_path): + subdir = tmp_path / "subdir" + result_file = str(subdir / "airflow_result.json") + ga.AIR_FLOW_CONF = {"fans": [], "psus": []} + + with patch.object(ga, 'AIRFLOW_RESULT_FILE', result_file): + ga.generate_airflow() + + assert os.path.exists(result_file) + + +class TestLogging: + """Tests for logging functions""" + + @patch('syslog.openlog') + @patch('syslog.syslog') + def test_airflow_info(self, mock_syslog, mock_openlog): + ga.airflow_info("test message") + mock_openlog.assert_called_once_with("AIRFLOW", ga.syslog.LOG_PID) + mock_syslog.assert_called_once_with(ga.syslog.LOG_INFO, "test message") + + @patch('syslog.openlog') + @patch('syslog.syslog') + def test_airflow_error(self, mock_syslog, mock_openlog): + ga.airflow_error("error message") + mock_openlog.assert_called_once_with("AIRFLOW", ga.syslog.LOG_PID) + mock_syslog.assert_called_once_with(ga.syslog.LOG_ERR, "error message") + + @patch('syslog.openlog') + @patch('syslog.syslog') + def test_airflow_debug_when_enabled(self, mock_syslog, mock_openlog): + ga.debuglevel = ga.AIRFLOWDEBUG + ga.airflow_debug("debug msg") + mock_syslog.assert_called_once() + ga.debuglevel = 0 + + @patch('syslog.syslog') + def test_airflow_debug_when_disabled(self, mock_syslog): + ga.debuglevel = 0 + ga.airflow_debug("debug msg") + mock_syslog.assert_not_called() diff --git a/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_platform_driver.py b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_platform_driver.py new file mode 100644 index 0000000000..fdbeea6542 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-ragile/common/script/tests/test_platform_driver.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +""" +Unit tests for platform_driver.py — focused on removeDev and addDev +""" + +import os +import sys +import pytest +from unittest.mock import patch, mock_open, MagicMock, call + +# Mock platform-specific imports +import types +mock_config = types.ModuleType('platform_config') +mock_config.GLOBALCONFIG = {"DRIVERLISTS": [], "DEVS": [], "OPTOE": []} +mock_config.WARM_UPGRADE_STARTED_FLAG = "/tmp/.warm_upgrade_started" +mock_config.WARM_UPG_FLAG = "/tmp/.warm_upg_flag" +sys.modules['platform_config'] = mock_config + +# Mock click +sys.modules['click'] = MagicMock() + +import platform_driver as pd + + +class TestRemoveDev: + """Tests for removeDev()""" + + @patch('os.path.exists', return_value=True) + def test_removes_existing_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + pd.removeDev(10, 0x56) + m.assert_called_once_with("/sys/bus/i2c/devices/i2c-10/delete_device", 'w') + m().write.assert_called_once_with("0x56\n") + + @patch('os.path.exists', return_value=False) + def test_skips_nonexistent_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + pd.removeDev(10, 0x56) + m.assert_not_called() + + @patch('os.path.exists', return_value=True) + def test_correct_devpath_format(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + pd.removeDev(5, 0x48) + mock_exists.assert_called_with("/sys/bus/i2c/devices/5-0048") + + +class TestAddDev: + """Tests for addDev()""" + + @patch('os.path.exists') + def test_adds_new_device(self, mock_exists): + # pdevpath exists, devpath does not + mock_exists.side_effect = lambda p: p.endswith("/") + m = mock_open() + with patch("builtins.open", m): + pd.addDev("tmp75", 10, 0x48) + m.assert_called_once_with("/sys/bus/i2c/devices/i2c-10/new_device", 'w') + m().write.assert_called_once_with("tmp75 0x48\n") + + @patch('os.path.exists', return_value=True) + def test_skips_existing_device(self, mock_exists): + m = mock_open() + with patch("builtins.open", m): + pd.addDev("tmp75", 10, 0x48) + m.assert_not_called() + + @patch('time.sleep') + @patch('os.path.exists') + def test_lm75_sleeps_before_add(self, mock_exists, mock_sleep): + mock_exists.side_effect = lambda p: p.endswith("/") + m = mock_open() + with patch("builtins.open", m): + pd.addDev("lm75", 10, 0x48) + mock_sleep.assert_any_call(0.1) + + @patch('os.path.exists') + def test_waits_for_parent_bus(self, mock_exists): + # Simulate parent bus appearing after 3 attempts + call_count = [0] + def side_effect(path): + if path.endswith("/"): + call_count[0] += 1 + return call_count[0] >= 3 + return False # devpath doesn't exist + + mock_exists.side_effect = side_effect + m = mock_open() + with patch("builtins.open", m), \ + patch('time.sleep'): + pd.addDev("tmp75", 10, 0x48) + m.assert_called_once() + + +class TestCheckDriver: + """Tests for check_driver()""" + + @patch.object(pd, 'log_os_system', return_value=(0, "3")) + def test_driver_loaded(self, mock_log): + assert pd.check_driver() is True + + @patch.object(pd, 'log_os_system', return_value=(0, "0")) + def test_driver_not_loaded(self, mock_log): + assert pd.check_driver() is False + + @patch.object(pd, 'log_os_system', return_value=(1, "")) + def test_command_fails(self, mock_log): + assert pd.check_driver() is False + + +class TestChecksignaldriver: + """Tests for checksignaldriver()""" + + @patch.object(pd, 'log_os_system', return_value=(0, "1")) + def test_module_loaded(self, mock_log): + assert pd.checksignaldriver("wb_io_dev") is True + + @patch.object(pd, 'log_os_system', return_value=(0, "0")) + def test_module_not_loaded(self, mock_log): + assert pd.checksignaldriver("wb_io_dev") is False + + @patch.object(pd, 'log_os_system', return_value=(1, "")) + def test_command_fails(self, mock_log): + assert pd.checksignaldriver("wb_io_dev") is False + + +class TestAddRemoveDriver: + """Tests for adddriver() and removedriver()""" + + @patch.object(pd, 'log_os_system') + @patch.object(pd, 'checksignaldriver', return_value=False) + def test_adddriver_loads_module(self, mock_check, mock_log): + pd.adddriver("wb_io_dev", 0) + mock_log.assert_called_once_with("modprobe wb_io_dev") + + @patch.object(pd, 'log_os_system') + @patch.object(pd, 'checksignaldriver', return_value=True) + def test_adddriver_skips_loaded_module(self, mock_check, mock_log): + pd.adddriver("wb_io_dev", 0) + mock_log.assert_not_called() + + @patch.object(pd, 'log_os_system') + @patch.object(pd, 'checksignaldriver', return_value=True) + def test_removedriver_removes_module(self, mock_check, mock_log): + pd.removedriver("wb_io_dev", 0) + mock_log.assert_called_once_with("rmmod -f wb_io_dev") + + @patch.object(pd, 'log_os_system') + @patch.object(pd, 'checksignaldriver', return_value=False) + def test_removedriver_skips_unloaded_module(self, mock_check, mock_log): + pd.removedriver("wb_io_dev", 0) + mock_log.assert_not_called() diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index e227944ccc..9e4f2a4d5f 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES. +# Copyright (c) 2016-2026 NVIDIA CORPORATION & AFFILIATES. # Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,34 +25,34 @@ SIMX_VERSION = 26.1-1164 FW_FROM_URL = y -MLNX_FW_ASSETS_RELEASE_TAG = fw-2016.3430 +MLNX_FW_ASSETS_RELEASE_TAG = fw-2016.3442 MLNX_FW_ASSETS_URL = $(MLNX_ASSETS_GITHUB_URL)/releases/download/$(MLNX_FW_ASSETS_RELEASE_TAG) ifeq ($(MLNX_FW_BASE_URL), ) MLNX_FW_BASE_URL = $(MLNX_FW_ASSETS_URL) endif -MLNX_SPC_FW_VERSION = 13.2016.3430 +MLNX_SPC_FW_VERSION = 13.2016.3442 MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa $(MLNX_SPC_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC_FW_FILE) -MLNX_SPC2_FW_VERSION = 29.2016.3430 +MLNX_SPC2_FW_VERSION = 29.2016.3442 MLNX_SPC2_FW_FILE = fw-SPC2-rel-$(subst .,_,$(MLNX_SPC2_FW_VERSION))-EVB.mfa $(MLNX_SPC2_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC2_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC2_FW_FILE) -MLNX_SPC3_FW_VERSION = 30.2016.3430 +MLNX_SPC3_FW_VERSION = 30.2016.3442 MLNX_SPC3_FW_FILE = fw-SPC3-rel-$(subst .,_,$(MLNX_SPC3_FW_VERSION))-EVB.mfa $(MLNX_SPC3_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC3_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC3_FW_FILE) -MLNX_SPC4_FW_VERSION = 34.2016.3430 +MLNX_SPC4_FW_VERSION = 34.2016.3442 MLNX_SPC4_FW_FILE = fw-SPC4-rel-$(subst .,_,$(MLNX_SPC4_FW_VERSION))-EVB.mfa $(MLNX_SPC4_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC4_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC4_FW_FILE) -MLNX_SPC5_FW_VERSION = 37.2016.3430 +MLNX_SPC5_FW_VERSION = 37.2016.3442 MLNX_SPC5_FW_FILE = fw-SPC5-rel-$(subst .,_,$(MLNX_SPC5_FW_VERSION))-EVB.mfa $(MLNX_SPC5_FW_FILE)_PATH = $(MLNX_FW_BASE_PATH) $(MLNX_SPC5_FW_FILE)_URL = $(MLNX_FW_BASE_URL)/$(MLNX_SPC5_FW_FILE) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 68d1b3d7ca..e38d7064ce 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -132,6 +132,8 @@ def __init__(self): # Mapping from SFP index to ASIC ID self._asic_id_map = None + self._num_npus = device_info.get_num_npus() + self.liquid_cooling = None Chassis.chassis_instance = self @@ -153,14 +155,14 @@ def __del__(self): @property def RJ45_port_list(self): if not self._RJ45_port_inited: - self._RJ45_port_list = extract_RJ45_ports_index() + self._RJ45_port_list = extract_RJ45_ports_index(self._num_npus) self._RJ45_port_inited = True return self._RJ45_port_list @property def cpo_port_list(self): if not self._cpo_port_inited: - self._cpo_port_list = extract_cpo_ports_index() + self._cpo_port_list = extract_cpo_ports_index(self._num_npus) self._cpo_port_inited = True return self._cpo_port_list @@ -364,11 +366,11 @@ def get_num_sfps(self): """ num_sfps = 0 if not self._RJ45_port_inited: - self._RJ45_port_list = extract_RJ45_ports_index() + self._RJ45_port_list = extract_RJ45_ports_index(self._num_npus) self._RJ45_port_inited = True - + if not self._cpo_port_inited: - self._cpo_port_list = extract_cpo_ports_index() + self._cpo_port_list = extract_cpo_ports_index(self._num_npus) self._cpo_port_inited = True num_sfps = DeviceDataManager.get_sfp_count() diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index c9667afbf8..ab2506ca48 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -1996,6 +1996,8 @@ def __init__(self, sfp_index, asic_id='asic0'): def get_transceiver_info(self): transceiver_info_dict = super().get_transceiver_info() + if transceiver_info_dict is None: + return None transceiver_info_dict['type'] = self.sfp_type return transceiver_info_dict diff --git a/platform/mellanox/rshim.mk b/platform/mellanox/rshim.mk index f956cdf79e..fffbd68781 100644 --- a/platform/mellanox/rshim.mk +++ b/platform/mellanox/rshim.mk @@ -15,7 +15,7 @@ # limitations under the License. # -MLNX_RSHIM_DRIVER_VERSION = 2.6.4 +MLNX_RSHIM_DRIVER_VERSION = 2.6.6 MLNX_RSHIM_ASSETS_GITHUB_URL = https://github.com/Mellanox/sonic-bluefield-packages MLNX_RSHIM_ASSETS_RELEASE_TAG = rshim-$(MLNX_RSHIM_DRIVER_VERSION)-$(BLDENV)-$(CONFIGURED_ARCH) MLNX_RSHIM_ASSETS_URL = $(MLNX_RSHIM_ASSETS_GITHUB_URL)/releases/download/$(MLNX_RSHIM_ASSETS_RELEASE_TAG) diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 6cd51f31f8..571b59def9 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,6 +1,6 @@ # # SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES -# Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# Copyright (c) 2021-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -MLNX_SDK_VERSION = 4.8.3430 +MLNX_SDK_VERSION = 4.8.3442 MLNX_SDK_ISSU_VERSION = 101 MLNX_SDK_DRIVERS_GITHUB_URL = https://github.com/Mellanox/Spectrum-SDK-Drivers diff --git a/platform/nvidia-bluefield/recipes/bluefield-soc.mk b/platform/nvidia-bluefield/recipes/bluefield-soc.mk index 9f5bbe6ffd..c7ab23f7a0 100644 --- a/platform/nvidia-bluefield/recipes/bluefield-soc.mk +++ b/platform/nvidia-bluefield/recipes/bluefield-soc.mk @@ -17,7 +17,7 @@ # Bluefied Software Distribution Version BFSOC_VERSION = 4.14.0 -BFSOC_REVISION = 13868 +BFSOC_REVISION = 13938 BFB_IMG_TYPE = prod BFSOC_BUILD_DATE = diff --git a/platform/nvidia-bluefield/recipes/fw.mk b/platform/nvidia-bluefield/recipes/fw.mk index e17582da33..02e97a2e40 100644 --- a/platform/nvidia-bluefield/recipes/fw.mk +++ b/platform/nvidia-bluefield/recipes/fw.mk @@ -19,7 +19,7 @@ DPU_NIC_FW_BASE_URL = DPU_NIC_FW_VERSION = BF3_FW_BASE_URL = -BF3_FW_VERSION = 48.0410 +BF3_FW_VERSION = 48.1000 BF3_FW_FILE = fw-BlueField-3-rel-32_$(subst .,_,$(BF3_FW_VERSION)).mfa diff --git a/platform/template/docker-syncd-trixie.mk b/platform/template/docker-syncd-trixie.mk index 2017c332d3..2fde6da915 100644 --- a/platform/template/docker-syncd-trixie.mk +++ b/platform/template/docker-syncd-trixie.mk @@ -6,7 +6,6 @@ DOCKER_SYNCD_BASE_DBG = $(DOCKER_SYNCD_BASE_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_SYNCD_BASE)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_PLATFORM_CODE) - $(DOCKER_SYNCD_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) $(DOCKER_SYNCD_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) diff --git a/platform/vs/docker-dash-engine.mk b/platform/vs/docker-dash-engine.mk index dcba3fe343..dbddffb7da 100644 --- a/platform/vs/docker-dash-engine.mk +++ b/platform/vs/docker-dash-engine.mk @@ -8,10 +8,8 @@ $(DOCKER_DASH_ENGINE)_PATH = $(PLATFORM_PATH)/docker-dash-engine SONIC_DOCKER_IMAGES += $(DOCKER_DASH_ENGINE) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_DASH_ENGINE) -$(DOCKER_DASH_ENGINE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) $(DOCKER_DASH_ENGINE)_CONTAINER_NAME = dash_engine $(DOCKER_DASH_ENGINE)_CONTAINER_PRIVILEGED = true $(DOCKER_DASH_ENGINE)_RUN_OPT += --privileged -t -SONIC_BOOKWORM_DOCKERS += $(DOCKER_DASH_ENGINE) diff --git a/rules/docker-bmp-watchdog.mk b/rules/docker-bmp-watchdog.mk index f4821f6658..c63c211f87 100644 --- a/rules/docker-bmp-watchdog.mk +++ b/rules/docker-bmp-watchdog.mk @@ -4,7 +4,7 @@ DOCKER_BMP_WATCHDOG_STEM = docker-bmp-watchdog DOCKER_BMP_WATCHDOG = $(DOCKER_BMP_WATCHDOG_STEM).gz DOCKER_BMP_WATCHDOG_DBG = $(DOCKER_BMP_WATCHDOG_STEM)-$(DBG_IMAGE_MARK).gz -$(DOCKER_BMP_WATCHDOG)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BOOKWORM) +$(DOCKER_BMP_WATCHDOG)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_TRIXIE) $(DOCKER_BMP_WATCHDOG)_PATH = $(DOCKERS_PATH)/$(DOCKER_BMP_WATCHDOG_STEM) @@ -12,11 +12,11 @@ $(DOCKER_BMP_WATCHDOG)_VERSION = 1.0.0 $(DOCKER_BMP_WATCHDOG)_PACKAGE_NAME = bmp_watchdog SONIC_DOCKER_IMAGES += $(DOCKER_BMP_WATCHDOG) -SONIC_BOOKWORM_DOCKERS += $(DOCKER_BMP_WATCHDOG) +SONIC_TRIXIE_DOCKERS += $(DOCKER_BMP_WATCHDOG) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_BMP_WATCHDOG) SONIC_DOCKER_DBG_IMAGES += $(DOCKER_BMP_WATCHDOG_DBG) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_BMP_WATCHDOG_DBG) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_BMP_WATCHDOG_DBG) SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_BMP_WATCHDOG_DBG) $(DOCKER_BMP_WATCHDOG)_CONTAINER_NAME = bmp_watchdog diff --git a/rules/docker-otel.mk b/rules/docker-otel.mk index 4c0a1346fc..5f3571db49 100644 --- a/rules/docker-otel.mk +++ b/rules/docker-otel.mk @@ -6,20 +6,20 @@ DOCKER_OTEL_DBG = $(DOCKER_OTEL_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_OTEL)_PATH = $(DOCKERS_PATH)/$(DOCKER_OTEL_STEM) -$(DOCKER_OTEL)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) -$(DOCKER_OTEL)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) +$(DOCKER_OTEL)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) +$(DOCKER_OTEL)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) $(DOCKER_OTEL)_VERSION = 1.0.0 $(DOCKER_OTEL)_PACKAGE_NAME = otel -$(DOCKER_OTEL)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) +$(DOCKER_OTEL)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) SONIC_DOCKER_IMAGES += $(DOCKER_OTEL) -SONIC_BOOKWORM_DOCKERS += $(DOCKER_OTEL) +SONIC_TRIXIE_DOCKERS += $(DOCKER_OTEL) ifeq ($(INCLUDE_SYSTEM_OTEL), y) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_OTEL) endif SONIC_DOCKER_DBG_IMAGES += $(DOCKER_OTEL_DBG) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_OTEL_DBG) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_OTEL_DBG) ifeq ($(INCLUDE_SYSTEM_OTEL), y) SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_OTEL_DBG) endif diff --git a/rules/docker-sysmgr.mk b/rules/docker-sysmgr.mk index b1c5920405..9cbf29154d 100644 --- a/rules/docker-sysmgr.mk +++ b/rules/docker-sysmgr.mk @@ -7,12 +7,12 @@ DOCKER_SYSMGR_DBG = $(DOCKER_SYSMGR_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_SYSMGR)_PATH = $(DOCKERS_PATH)/$(DOCKER_SYSMGR_STEM) $(DOCKER_SYSMGR)_DEPENDS += $(SYSMGR) -$(DOCKER_SYSMGR)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) +$(DOCKER_SYSMGR)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_DEPENDS) $(DOCKER_SYSMGR)_DBG_DEPENDS += $(SYSMGR_DBG) $(LIBSWSSCOMMON_DBG) -$(DOCKER_SYSMGR)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) +$(DOCKER_SYSMGR)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_TRIXIE)_DBG_IMAGE_PACKAGES) -$(DOCKER_SYSMGR)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BOOKWORM) -$(DOCKER_SYSMGR)_LOAD_DOCKERS += $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_LOAD_DOCKERS) +$(DOCKER_SYSMGR)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_TRIXIE) +$(DOCKER_SYSMGR)_LOAD_DOCKERS += $($(DOCKER_CONFIG_ENGINE_TRIXIE)_LOAD_DOCKERS) $(DOCKER_SYSMGR)_VERSION = 1.0.0 $(DOCKER_SYSMGR)_PACKAGE_NAME = sysmgr @@ -30,5 +30,5 @@ $(DOCKER_SYSMGR)_GIT_REPOSITORIES += "sonic-swss" $(DOCKER_SYSMGR)_GIT_REPOSITORIES += "sonic-swss-common" -SONIC_BOOKWORM_DOCKERS += $(DOCKER_SYSMGR) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_SYSMGR_DBG) +SONIC_TRIXIE_DOCKERS += $(DOCKER_SYSMGR) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_SYSMGR_DBG) diff --git a/rules/docker-telemetry-sidecar.mk b/rules/docker-telemetry-sidecar.mk index 13edf09934..34f426529a 100644 --- a/rules/docker-telemetry-sidecar.mk +++ b/rules/docker-telemetry-sidecar.mk @@ -4,7 +4,7 @@ DOCKER_TELEMETRY_SIDECAR_STEM = docker-telemetry-sidecar DOCKER_TELEMETRY_SIDECAR = $(DOCKER_TELEMETRY_SIDECAR_STEM).gz DOCKER_TELEMETRY_SIDECAR_DBG = $(DOCKER_TELEMETRY_SIDECAR_STEM)-$(DBG_IMAGE_MARK).gz -$(DOCKER_TELEMETRY_SIDECAR)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BOOKWORM) +$(DOCKER_TELEMETRY_SIDECAR)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_TRIXIE) $(DOCKER_TELEMETRY_SIDECAR)_PATH = $(DOCKERS_PATH)/$(DOCKER_TELEMETRY_SIDECAR_STEM) @@ -12,11 +12,11 @@ $(DOCKER_TELEMETRY_SIDECAR)_VERSION = 1.0.0 $(DOCKER_TELEMETRY_SIDECAR)_PACKAGE_NAME = telemetry-sidecar SONIC_DOCKER_IMAGES += $(DOCKER_TELEMETRY_SIDECAR) -SONIC_BOOKWORM_DOCKERS += $(DOCKER_TELEMETRY_SIDECAR) +SONIC_TRIXIE_DOCKERS += $(DOCKER_TELEMETRY_SIDECAR) SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_TELEMETRY_SIDECAR) SONIC_DOCKER_DBG_IMAGES += $(DOCKER_TELEMETRY_SIDECAR_DBG) -SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_TELEMETRY_SIDECAR_DBG) +SONIC_TRIXIE_DBG_DOCKERS += $(DOCKER_TELEMETRY_SIDECAR_DBG) SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_TELEMETRY_SIDECAR_DBG) diff --git a/slave.mk b/slave.mk index 7531d3028a..eb135390fe 100644 --- a/slave.mk +++ b/slave.mk @@ -1500,6 +1500,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(SONIC_CTRMGRD_RS) \ $(SONIC_HOST_SERVICES_RS) \ $(SONIC_HOST_SERVICES_DATA) \ + $(SOCAT) \ $(BASH) \ $(BASH_TACPLUS) \ $(AUDISP_TACPLUS) \ @@ -1582,7 +1583,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export include_kubernetes_master="$(INCLUDE_KUBERNETES_MASTER)" export kube_docker_proxy="$(KUBE_DOCKER_PROXY)" export enable_pfcwd_on_start="$(ENABLE_PFCWD_ON_START)" - export installer_debs="$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$($*_INSTALLS) $(FIPS_BASEIMAGE_INSTALLERS))" + export installer_debs="$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$($*_INSTALLS) $(FIPS_BASEIMAGE_INSTALLERS) $(SOCAT))" export installer_python_debs="$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(FIPS_BASEIMAGE_PYTHON_INSTALLERS))" export lazy_installer_debs="$(foreach deb, $($*_LAZY_INSTALLS),$(foreach device, $($(deb)_PLATFORM),$(addprefix $(device)@, $(IMAGE_DISTRO_DEBS_PATH)/$(deb))))" export lazy_build_installer_debs="$(foreach deb, $($*_LAZY_BUILD_INSTALLS), $(addprefix $($(deb)_MACHINE)|,$(deb)))" diff --git a/sonic-slave-trixie/Dockerfile.j2 b/sonic-slave-trixie/Dockerfile.j2 index c527bda4be..a2458a38d8 100644 --- a/sonic-slave-trixie/Dockerfile.j2 +++ b/sonic-slave-trixie/Dockerfile.j2 @@ -75,7 +75,7 @@ RUN pip3 install virtualenv RUN mkdir /python_virtualenv RUN cd /python_virtualenv && python3 -m virtualenv --copies -p /usr/bin/python3 env3 -RUN PATH=/python_virtualenv/env3/bin/:$PATH pip3 install setuptools==75.8.0 setuptools-scm==8.2.1 wheel==0.45.1 fastentrypoints pytest pytest-cov pytest-runner==5.2 nose==1.3.7 mockredispy==2.9.3 mock==3.0.5 PyYAML==6.0.2 redis==3.5.3 pexpect==4.8.0 Pympler==0.8 parameterized natsort==6.2.1 MarkupSafe==2.0.1 Jinja2==3.0.3 click tabulate netaddr netifaces pyroute2 pyfakefs sphinx && ln -s /python_virtualenv/env3/bin/pytest /python_virtualenv/env3/bin/pytest-3"," +RUN PATH=/python_virtualenv/env3/bin/:$PATH pip3 install setuptools==75.8.0 setuptools-scm==8.2.1 setuptools-scm-git-archive==1.4.1 wheel==0.45.1 fastentrypoints pytest pytest-cov pytest-runner==5.2 nose==1.3.7 mockredispy==2.9.3 mock==3.0.5 PyYAML==6.0.2 redis==3.5.3 pexpect==4.8.0 Pympler==0.8 parameterized natsort==6.2.1 MarkupSafe==2.0.1 Jinja2==3.0.3 click tabulate netaddr netifaces pyroute2 pyfakefs sphinx && ln -s /python_virtualenv/env3/bin/pytest /python_virtualenv/env3/bin/pytest-3"," RUN eatmydata apt-get --fix-broken install -y RUN LIBPYTHON3_DEPS="`apt-cache depends libpython3-dev:$arch |grep Depends|awk {'print \$2;'}|tr "\n" " "`" && apt-get install -y libpython2.7-dev:$arch $LIBPYTHON3_DEPS libxml2-dev:$arch libxslt-dev:$arch libssl-dev:$arch libz-dev:$arch @@ -619,10 +619,9 @@ RUN pip3 install pyang==2.4.0 # For mgmt-framework build RUN pip3 install mmh3==2.5.1 -# For ptf-py3 0.10.0 -#RUN pip3 install setuptools==75.8.0 setuptools-scm==8.2.1 setuptools-scm-git-archive==1.4.1 -# remove - setuptools-scm-git-archive - setuptools-scm 8 [1] and redundant starting with setuptools-scm 7 [2] -RUN pip3 install setuptools==75.8.0 setuptools-scm==8.2.1 +# PEP 517 wheels (e.g. src/ptf-py3): slave.mk runs "python -m build -n" without isolation, so [build-system] +# requires must be present on the host interpreter (pip install . alone uses an isolated build env). +RUN pip3 install setuptools==75.8.0 setuptools-scm==8.2.1 setuptools-scm-git-archive==1.4.1 wheel RUN eatmydata apt-get install -y xsltproc diff --git a/src/dhcprelay b/src/dhcprelay index 7316417034..d7a78ba486 160000 --- a/src/dhcprelay +++ b/src/dhcprelay @@ -1 +1 @@ -Subproject commit 7316417034fee6a6c6002490362c9bc75eeafde1 +Subproject commit d7a78ba4860396ed37fa4a12e38c4d18b09087c2 diff --git a/src/sonic-config-engine/tests/sample_output/py3/buffer-lrh-nh5010.json b/src/sonic-config-engine/tests/sample_output/py3/buffer-lrh-nh5010.json index 026d5165f7..9785f1d314 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/buffer-lrh-nh5010.json +++ b/src/sonic-config-engine/tests/sample_output/py3/buffer-lrh-nh5010.json @@ -76,7 +76,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/src/sonic-config-engine/tests/sample_output/py3/buffer-urh-nh5010.json b/src/sonic-config-engine/tests/sample_output/py3/buffer-urh-nh5010.json index 026d5165f7..9785f1d314 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/buffer-urh-nh5010.json +++ b/src/sonic-config-engine/tests/sample_output/py3/buffer-urh-nh5010.json @@ -76,7 +76,7 @@ "size": "25766440000", "type": "both", "mode": "dynamic", - "xoff": "5301600256" + "xoff": "4024103375" } }, "BUFFER_PROFILE": { diff --git a/src/sonic-host-services b/src/sonic-host-services index 2feaf80e59..c5bbbe8b07 160000 --- a/src/sonic-host-services +++ b/src/sonic-host-services @@ -1 +1 @@ -Subproject commit 2feaf80e590e6fef20dff1610e9f52884385ffd6 +Subproject commit c5bbbe8b07b96f078fa4b761316627404b01bd04 diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index 15a20e6249..41faa18b53 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit 15a20e6249f9c30fda362a957ac7c32d787e1477 +Subproject commit 41faa18b5399dfe4bcbd595034df87b01f3be6f3 diff --git a/src/sonic-py-common/sonic_py_common/sidecar_common.py b/src/sonic-py-common/sonic_py_common/sidecar_common.py index b0628c80e6..0a8575b684 100644 --- a/src/sonic-py-common/sonic_py_common/sidecar_common.py +++ b/src/sonic-py-common/sonic_py_common/sidecar_common.py @@ -274,3 +274,25 @@ def _run_host_actions_for(path_on_host: str, post_copy_actions: Dict[str, List[L logger.log_info(f"Post-copy action succeeded: {' '.join(cmd)}") else: logger.log_error(f"Post-copy action FAILED (rc={rc}): {' '.join(cmd)}; stderr={str(err).strip()}") + + +def cleanup_native_container(container_name: str, is_v1_enabled: bool) -> None: + """In V2 mode, check for and remove any native container. + + Post-copy actions only fire when a synced file changes, so on subsequent + sidecar restarts (files already in sync) or after a race with the + container framework, the native container may persist. Called every + sync cycle to guarantee it is eventually cleaned up. + """ + if is_v1_enabled: + return + rc, out, _ = run_nsenter( + ["sudo", "docker", "inspect", "--format", "{{.State.Status}}", container_name] + ) + if rc != 0: + logger.log_info(f"No native {container_name} container found") + return + status = out.strip() + logger.log_notice(f"Native {container_name} container found (status={status}); removing") + run_nsenter(["sudo", "docker", "stop", container_name]) + run_nsenter(["sudo", "docker", "rm", "--force", container_name]) diff --git a/src/sonic-py-common/tests/test_sidecar_common.py b/src/sonic-py-common/tests/test_sidecar_common.py index b7b1310a33..c9bdf3670a 100644 --- a/src/sonic-py-common/tests/test_sidecar_common.py +++ b/src/sonic-py-common/tests/test_sidecar_common.py @@ -193,3 +193,90 @@ def fake_read_file_bytes_local(path): sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] assert ("sudo", "systemctl", "daemon-reload") in sudo_cmds assert ("sudo", "systemctl", "restart", "myservice") in sudo_cmds + + +# ─────────────────────────── Tests for cleanup_native_container ─────────────────────────── + +@pytest.fixture +def docker_nsenter(monkeypatch): + """Mock run_nsenter with configurable docker inspect response.""" + commands = [] + inspect_result = {"rc": 1, "out": "", "err": ""} + + def fake_run_nsenter(args, *, text=True, input_bytes=None): + commands.append(("nsenter", tuple(args))) + if args[:2] == ["sudo", "docker"] and "inspect" in args: + return inspect_result["rc"], inspect_result["out"], inspect_result["err"] + if args[:1] == ["sudo"]: + return 0, "" if text else b"", "" if text else b"" + return 1, "" if text else b"", "unsupported" if text else b"unsupported" + + monkeypatch.setattr(sidecar_common, "run_nsenter", fake_run_nsenter) + return commands, inspect_result + + +def test_cleanup_native_container_removes_running(fake_logger, docker_nsenter): + """When a native container is running, it is stopped and force-removed.""" + commands, inspect_result = docker_nsenter + inspect_result.update(rc=0, out="running\n", err="") + + sidecar_common.cleanup_native_container("mycontainer", False) + + sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] + assert ("sudo", "docker", "inspect", "--format", "{{.State.Status}}", "mycontainer") in sudo_cmds + assert ("sudo", "docker", "stop", "mycontainer") in sudo_cmds + assert ("sudo", "docker", "rm", "--force", "mycontainer") in sudo_cmds + + +def test_cleanup_native_container_removes_exited(fake_logger, docker_nsenter): + """When a native container exists but is exited, it is still removed.""" + commands, inspect_result = docker_nsenter + inspect_result.update(rc=0, out="exited\n", err="") + + sidecar_common.cleanup_native_container("mycontainer", False) + + sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] + assert ("sudo", "docker", "stop", "mycontainer") in sudo_cmds + assert ("sudo", "docker", "rm", "--force", "mycontainer") in sudo_cmds + + +def test_cleanup_native_container_noop_when_absent(fake_logger, docker_nsenter): + """When no native container exists, cleanup is a no-op.""" + commands, inspect_result = docker_nsenter + inspect_result.update(rc=1, out="", err="No such object: mycontainer") + + sidecar_common.cleanup_native_container("mycontainer", False) + + sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] + assert ("sudo", "docker", "stop", "mycontainer") not in sudo_cmds + assert ("sudo", "docker", "rm", "--force", "mycontainer") not in sudo_cmds + + +def test_cleanup_native_container_skipped_when_v1(fake_logger, docker_nsenter): + """When is_v1_enabled=True, native container cleanup is skipped entirely.""" + commands, _ = docker_nsenter + + sidecar_common.cleanup_native_container("mycontainer", True) + + assert len(commands) == 0 + + +def test_cleanup_native_container_uses_container_name(fake_logger, docker_nsenter): + """Container name parameter is correctly passed to all docker commands.""" + commands, inspect_result = docker_nsenter + inspect_result.update(rc=0, out="running\n", err="") + + sidecar_common.cleanup_native_container("restapi", False) + + sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] + assert ("sudo", "docker", "stop", "restapi") in sudo_cmds + assert ("sudo", "docker", "rm", "--force", "restapi") in sudo_cmds + + commands.clear() + inspect_result.update(rc=0, out="running\n", err="") + + sidecar_common.cleanup_native_container("acms", False) + + sudo_cmds = [args for _, args in commands if args and args[0] == "sudo"] + assert ("sudo", "docker", "stop", "acms") in sudo_cmds + assert ("sudo", "docker", "rm", "--force", "acms") in sudo_cmds diff --git a/src/sonic-redfish b/src/sonic-redfish index 573a26dcc8..2d214870e7 160000 --- a/src/sonic-redfish +++ b/src/sonic-redfish @@ -1 +1 @@ -Subproject commit 573a26dcc8c5c81b9506332e4e909da96e0b945d +Subproject commit 2d214870e71451122efe5518c238e000db490f07 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 82709a88f5..88bc51ae95 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 82709a88f5f552fca7f3c7e99eda1806449190ff +Subproject commit 88bc51ae95df66977601957515e5527119ffd4c5 diff --git a/src/sonic-swss b/src/sonic-swss index 79fa04b145..4305596156 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 79fa04b14583827e2d77bfdec612ee3806582752 +Subproject commit 4305596156d70e9797e8a881b3d19b46de0bce0d diff --git a/src/sonic-utilities b/src/sonic-utilities index c94d0032be..39732bceb8 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit c94d0032be1061ce7497a55c2d7fbd2469f2cee5 +Subproject commit 39732bceb8bdefe706518ab40623bbbba6ff33b9 diff --git a/src/sonic-yang-models/tests/files/sample_config_db.json b/src/sonic-yang-models/tests/files/sample_config_db.json index f9a16ff372..c4551ca50a 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -2200,7 +2200,7 @@ "link_selection": "enable", "vrf_selection": "enable", "server_id_override": "enable", - "agent_relay_mode": "forward_untouched", + "agent_relay_mode": "discard", "max_hop_count": "4" }, "Vlan222": { @@ -2944,6 +2944,9 @@ "CONSOLE_SWITCH": { "console_mgmt": { "enabled": "yes" + }, + "controlled_device": { + "enabled": "yes" } }, "STATIC_ROUTE": { diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/console.json b/src/sonic-yang-models/tests/yang_model_tests/tests/console.json index efa0e84cf8..a605307ced 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/console.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/console.json @@ -11,6 +11,22 @@ "value": "no" } }, + "CONSOLE_DEFAULT_CONTROLLED_DEVICE": { + "desc": "CONSOLE_SWITCH default value for controlled_device enabled field.", + "eStrKey": "Verify", + "verify": { + "xpath": "/sonic-console:sonic-console/CONSOLE_SWITCH/controlled_device/enabled", + "key": "sonic-console:enabled", + "value": "no" + } + }, + "CONSOLE_VALID_CONTROLLED_DEVICE": { + "desc": "Verifying CONSOLE_SWITCH controlled_device configuration." + }, + "CONSOLE_CONTROLLED_DEVICE_INCORRECT_PATTERN": { + "desc": "CONSOLE_SWITCH controlled_device configuration pattern failure.", + "eStrKey": "Pattern" + }, "CONSOLE_DISABLED_INCORRECT_PATTERN": { "desc": "CONSOLE_SWITCH configuration pattern failure.", "eStrKey": "Pattern" diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/dhcpv4_relay.json b/src/sonic-yang-models/tests/yang_model_tests/tests/dhcpv4_relay.json index 8bfb0481a3..54d91ee112 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/dhcpv4_relay.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/dhcpv4_relay.json @@ -12,7 +12,16 @@ "desc": "Add dhcpv4 relay with link-select option enabled." }, "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_DISCARD": { - "desc": "Add dhcpv4 relay with minimum config." + "desc": "Add dhcpv4 relay with agent_relay_mode set to discard." + }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_APPEND": { + "desc": "Add dhcpv4 relay with agent_relay_mode set to append." + }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_REPLACE": { + "desc": "Add dhcpv4 relay with agent_relay_mode set to replace." + }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_FORWARD": { + "desc": "Add dhcpv4 relay with agent_relay_mode set to forward." }, "DHCPv4_RELAY_WITH_VALID_MAX_HOP_CNT": { "desc": "Add dhcpv4 relay with valid max_hop_cnt." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/console.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/console.json index 3cd7dc3105..467d1e5335 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/console.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/console.json @@ -16,6 +16,32 @@ } } }, + "CONSOLE_DEFAULT_CONTROLLED_DEVICE": { + "sonic-console:sonic-console": { + "sonic-console:CONSOLE_SWITCH": { + "sonic-console:controlled_device": { + } + } + } + }, + "CONSOLE_VALID_CONTROLLED_DEVICE": { + "sonic-console:sonic-console": { + "sonic-console:CONSOLE_SWITCH": { + "sonic-console:controlled_device": { + "enabled": "yes" + } + } + } + }, + "CONSOLE_CONTROLLED_DEVICE_INCORRECT_PATTERN": { + "sonic-console:sonic-console": { + "sonic-console:CONSOLE_SWITCH": { + "sonic-console:controlled_device": { + "enabled": "true" + } + } + } + }, "CONSOLE_DISABLED_INCORRECT_PATTERN": { "sonic-console:sonic-console": { "sonic-console:CONSOLE_SWITCH": { diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/dhcpv4_relay.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/dhcpv4_relay.json index 390c26653a..4ca652ad07 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/dhcpv4_relay.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/dhcpv4_relay.json @@ -105,6 +105,51 @@ } } }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_APPEND": { + "sonic-dhcpv4-relay:sonic-dhcpv4-relay": { + "sonic-dhcpv4-relay:DHCPV4_RELAY": { + "DHCPV4_RELAY_LIST": [ + { + "name": "Vlan777", + "dhcpv4_servers": [ + "192.168.20.100" + ], + "agent_relay_mode": "append" + } + ] + } + } + }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_REPLACE": { + "sonic-dhcpv4-relay:sonic-dhcpv4-relay": { + "sonic-dhcpv4-relay:DHCPV4_RELAY": { + "DHCPV4_RELAY_LIST": [ + { + "name": "Vlan777", + "dhcpv4_servers": [ + "192.168.20.100" + ], + "agent_relay_mode": "replace" + } + ] + } + } + }, + "DHCPv4_RELAY_WITH_AGENT_RELAY_MODE_FORWARD": { + "sonic-dhcpv4-relay:sonic-dhcpv4-relay": { + "sonic-dhcpv4-relay:DHCPV4_RELAY": { + "DHCPV4_RELAY_LIST": [ + { + "name": "Vlan777", + "dhcpv4_servers": [ + "192.168.20.100" + ], + "agent_relay_mode": "forward" + } + ] + } + } + }, "DHCPv4_RELAY_WITH_VALID_MAX_HOP_CNT": { "sonic-dhcpv4-relay:sonic-dhcpv4-relay": { "sonic-dhcpv4-relay:DHCPV4_RELAY": { diff --git a/src/sonic-yang-models/yang-models/sonic-console.yang b/src/sonic-yang-models/yang-models/sonic-console.yang index d6f886a7ea..e7ebe131dd 100644 --- a/src/sonic-yang-models/yang-models/sonic-console.yang +++ b/src/sonic-yang-models/yang-models/sonic-console.yang @@ -92,6 +92,14 @@ module sonic-console { } } + container controlled_device { + leaf enabled { + description "This configuration indicate if enable controlled device feature on SONiC"; + type console-mgmt-enabled; + default "no"; + } + } + } /* end of container CONSOLE_SWITCH */ } /* end of top level container */ diff --git a/src/sonic-yang-models/yang-models/sonic-dhcpv4-relay.yang b/src/sonic-yang-models/yang-models/sonic-dhcpv4-relay.yang index e05a79cb70..53f64dc8c3 100644 --- a/src/sonic-yang-models/yang-models/sonic-dhcpv4-relay.yang +++ b/src/sonic-yang-models/yang-models/sonic-dhcpv4-relay.yang @@ -118,7 +118,7 @@ module sonic-dhcpv4-relay { leaf agent_relay_mode { description "How to forward packets that already have a relay option"; type stypes:relay-agent-mode; - default forward_untouched; + default discard; } leaf max_hop_count { diff --git a/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 b/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 index 8620844bcb..dea15e8daa 100644 --- a/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 +++ b/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 @@ -532,20 +532,20 @@ module sonic-types { typedef relay-agent-mode { type enumeration { - enum forward_and_append { - description "Forward and append our own relay option"; + enum append { + description "Forward and append our own Option 82"; } - enum forward_and_replace { - description "Forward, but replace theirs with ours"; + enum replace { + description "Strip existing Option 82, add ours, and forward"; } - enum forward_untouched { - description "Forward without changes"; + enum forward { + description "Forward unchanged without modifying Option 82"; } enum discard { description "Discard the packet"; } } - description "This enumeration type defines what to do about a dhcp packets that already has a relay option."; + description "This enumeration type defines what to do about a dhcp packet that already has a relay option."; } {% if yang_model_type == "cvl" %}