@@ -388,6 +388,7 @@ type Chain struct {
388
388
389
389
// BaseChainInfo stores hook-related info for attaching a chain to the pipeline.
390
390
type BaseChainInfo struct {
391
+ // LINT.IfChange(base_chain_info)
391
392
392
393
// BcType is the base chain type of the chain (filter, nat, route).
393
394
BcType BaseChainType
@@ -414,6 +415,8 @@ type BaseChainInfo struct {
414
415
// explicitly accepted or rejected by the rules. A chain's policy defaults to
415
416
// Accept, but this can be used to specify otherwise.
416
417
PolicyDrop bool
418
+
419
+ // LINT.ThenChange(:base_chain_info_copy)
417
420
}
418
421
419
422
// PolicyBoolToValue converts the policy drop boolean to a uint8.
@@ -1109,3 +1112,130 @@ func HasAttr(attrName uint16, attrs map[uint16]nlmsg.BytesView) bool {
1109
1112
_ , ok := attrs [attrName ]
1110
1113
return ok
1111
1114
}
1115
+
1116
+ // deepCopyRule returns a deep copy of the Rule struct.
1117
+ func deepCopyRule (rule * Rule , chainCopy * Chain ) * Rule {
1118
+ return & Rule {
1119
+ chain : chainCopy ,
1120
+ // Because the underlying op data within the slice cannot be
1121
+ // modified, creating a shallow copy is sufficient. Even if the
1122
+ // original struct is modified and an operation is dropped,
1123
+ // the copy will hold a reference to the original operation,
1124
+ // preventing it from being destroyed.
1125
+ ops : slices .Clone (rule .ops ),
1126
+ handle : rule .handle ,
1127
+ udata : slices .Clone (rule .udata ),
1128
+ }
1129
+ }
1130
+
1131
+ // deepCopyChain returns a deep copy of the Chain struct.
1132
+ func deepCopyChain (chain * Chain , tableCopy * Table ) * Chain {
1133
+ chainCopy := & Chain {
1134
+ name : chain .name ,
1135
+ table : tableCopy ,
1136
+ handle : chain .handle ,
1137
+ flags : chain .flags ,
1138
+ handleToRule : make (map [uint64 ]* Rule ),
1139
+ userData : slices .Clone (chain .userData ),
1140
+ chainUse : chain .chainUse ,
1141
+ bound : chain .bound ,
1142
+ comment : chain .comment ,
1143
+ }
1144
+
1145
+ // LINT.IfChange(base_chain_info_copy)
1146
+
1147
+ // BaseChainInfo is immutable after creation and it only contains
1148
+ // primitives, so we can safely copy it.
1149
+ if chain .baseChainInfo != nil {
1150
+ chainCopy .baseChainInfo = & BaseChainInfo {}
1151
+ * chainCopy .baseChainInfo = * chain .baseChainInfo
1152
+ }
1153
+
1154
+ // LINT.ThenChange()
1155
+
1156
+ for _ , rule := range chain .rules {
1157
+ ruleCopy := deepCopyRule (rule , chainCopy )
1158
+ chainCopy .rules = append (chainCopy .rules , ruleCopy )
1159
+ chainCopy .handleToRule [ruleCopy .handle ] = ruleCopy
1160
+ }
1161
+ return chainCopy
1162
+ }
1163
+
1164
+ // deepCopyTable returns a deep copy of the Table struct.
1165
+ func deepCopyTable (table * Table , afFilter * addressFamilyFilter ) * Table {
1166
+ tableCopy := & Table {
1167
+ name : table .name ,
1168
+ afFilter : afFilter ,
1169
+ chains : make (map [string ]* Chain ),
1170
+ chainHandles : make (map [uint64 ]* Chain ),
1171
+ flagSet : make (map [TableFlag ]struct {}),
1172
+ handle : table .handle ,
1173
+ owner : table .owner ,
1174
+ userData : slices .Clone (table .userData ),
1175
+ }
1176
+ tableCopy .handleCounter .Store (table .handleCounter .Load ())
1177
+
1178
+ for flag := range table .flagSet {
1179
+ tableCopy .flagSet [flag ] = struct {}{}
1180
+ }
1181
+
1182
+ for chainName , chain := range table .chains {
1183
+ chainCopy := deepCopyChain (chain , tableCopy )
1184
+ tableCopy .chains [chainName ] = chainCopy
1185
+ tableCopy .chainHandles [chainCopy .handle ] = chainCopy
1186
+ }
1187
+ return tableCopy
1188
+ }
1189
+
1190
+ // DeepCopy returns a deep copy of the NFTables struct.
1191
+ // Assumes that the caller has already locked the mutex.
1192
+ // **********************************************************************
1193
+ // TODO: b/436922484: Add a transaction system to avoid deep copying the entire
1194
+ // NFTables structure.
1195
+ // **********************************************************************
1196
+ func (nf * NFTables ) DeepCopy () * NFTables {
1197
+ nftCopy := & NFTables {
1198
+ clock : nf .clock ,
1199
+ startTime : nf .startTime ,
1200
+ rng : nf .rng ,
1201
+ tableHandleCounter : atomicbitops.Uint64 {},
1202
+ }
1203
+
1204
+ nftCopy .tableHandleCounter .Store (nf .tableHandleCounter .Load ())
1205
+ for i , filter := range nf .filters {
1206
+ if filter == nil {
1207
+ continue
1208
+ }
1209
+
1210
+ nftCopy .filters [i ] = & addressFamilyFilter {
1211
+ family : filter .family ,
1212
+ nftState : nftCopy ,
1213
+ tables : make (map [string ]* Table ),
1214
+ tableHandles : make (map [uint64 ]* Table ),
1215
+ hfStacks : make (map [stack.NFHook ]* hookFunctionStack ),
1216
+ }
1217
+
1218
+ for tableName , table := range filter .tables {
1219
+ tableCopy := deepCopyTable (table , nftCopy .filters [i ])
1220
+ nftCopy .filters [i ].tables [tableName ] = tableCopy
1221
+ nftCopy .filters [i ].tableHandles [tableCopy .handle ] = tableCopy
1222
+ }
1223
+
1224
+ for hook , hfStack := range filter .hfStacks {
1225
+ hfStackCopy := & hookFunctionStack {
1226
+ hook : hfStack .hook ,
1227
+ }
1228
+ for _ , chain := range hfStack .baseChains {
1229
+ hfStackCopy .baseChains = append (hfStackCopy .baseChains , nftCopy .filters [i ].tables [chain .table .name ].chains [chain .name ])
1230
+ }
1231
+ nftCopy .filters [i ].hfStacks [hook ] = hfStackCopy
1232
+ }
1233
+ }
1234
+ return nftCopy
1235
+ }
1236
+
1237
+ // ReplaceNFTables replaces the tables of the NFTables struct
1238
+ // with the tables of the passed in NFTables struct.
1239
+ func (nf * NFTables ) ReplaceNFTables (nftCopy * NFTables ) {
1240
+ nf .filters = nftCopy .filters
1241
+ }
0 commit comments