1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.net;
17 
18 import android.os.Build;
19 import android.system.ErrnoException;
20 import android.util.IndentingPrintWriter;
21 import android.util.Log;
22 
23 import androidx.annotation.RequiresApi;
24 
25 import com.android.internal.annotations.VisibleForTesting;
26 import com.android.net.module.util.BpfDump;
27 import com.android.net.module.util.BpfMap;
28 import com.android.net.module.util.IBpfMap;
29 import com.android.net.module.util.Struct.S32;
30 
31 /**
32  * Monitor interface added (without removed) and right interface name and its index to bpf map.
33  */
34 @RequiresApi(Build.VERSION_CODES.TIRAMISU)
35 public class BpfInterfaceMapHelper {
36     private static final String TAG = BpfInterfaceMapHelper.class.getSimpleName();
37     // This is current path but may be changed soon.
38     private static final String IFACE_INDEX_NAME_MAP_PATH =
39             "/sys/fs/bpf/netd_shared/map_netd_iface_index_name_map";
40     private final IBpfMap<S32, InterfaceMapValue> mIndexToIfaceBpfMap;
41 
BpfInterfaceMapHelper()42     public BpfInterfaceMapHelper() {
43         this(new Dependencies());
44     }
45 
46     @VisibleForTesting
BpfInterfaceMapHelper(Dependencies deps)47     public BpfInterfaceMapHelper(Dependencies deps) {
48         mIndexToIfaceBpfMap = deps.getInterfaceMap();
49     }
50 
51     /**
52      * Dependencies of BpfInerfaceMapUpdater, for injection in tests.
53      */
54     @VisibleForTesting
55     public static class Dependencies {
56         /** Create BpfMap for updating interface and index mapping. */
getInterfaceMap()57         public IBpfMap<S32, InterfaceMapValue> getInterfaceMap() {
58             try {
59                 return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH,
60                     S32.class, InterfaceMapValue.class);
61             } catch (ErrnoException e) {
62                 Log.e(TAG, "Cannot create interface map: " + e);
63                 return null;
64             }
65         }
66     }
67 
68     /** get interface name by interface index from bpf map */
getIfNameByIndex(final int index)69     public String getIfNameByIndex(final int index) {
70         try {
71             final InterfaceMapValue value = mIndexToIfaceBpfMap.getValue(new S32(index));
72             if (value == null) {
73                 Log.e(TAG, "No if name entry for index " + index);
74                 return null;
75             }
76             return value.getInterfaceNameString();
77         } catch (ErrnoException e) {
78             Log.e(TAG, "Failed to get entry for index " + index + ": " + e);
79             return null;
80         }
81     }
82 
83     /**
84      * Dump BPF map
85      *
86      * @param pw print writer
87      */
dump(final IndentingPrintWriter pw)88     public void dump(final IndentingPrintWriter pw) {
89         pw.println("BPF map status:");
90         pw.increaseIndent();
91         BpfDump.dumpMapStatus(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
92                 IFACE_INDEX_NAME_MAP_PATH);
93         pw.decreaseIndent();
94         pw.println("BPF map content:");
95         pw.increaseIndent();
96         BpfDump.dumpMap(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
97                 (key, value) -> "ifaceIndex=" + key.val
98                         + " ifaceName=" + value.getInterfaceNameString());
99         pw.decreaseIndent();
100     }
101 }
102