github.com/cilium/cilium@v1.16.2/pkg/maps/ctmap/lookup.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package ctmap
     5  
     6  import (
     7  	"fmt"
     8  	"net/netip"
     9  
    10  	"github.com/cilium/cilium/pkg/bpf"
    11  	"github.com/cilium/cilium/pkg/tuple"
    12  	"github.com/cilium/cilium/pkg/u8proto"
    13  )
    14  
    15  func createTupleKey(isGlobal bool, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool) (bpf.MapKey, bool, error) {
    16  	srcAddrPort, err := netip.ParseAddrPort(srcAddr)
    17  	if err != nil {
    18  		return nil, false, fmt.Errorf("invalid source address '%s': %w", srcAddr, err)
    19  	}
    20  
    21  	dstAddrPort, err := netip.ParseAddrPort(dstAddr)
    22  	if err != nil {
    23  		return nil, false, fmt.Errorf("invalid destination address '%s': %w", dstAddr, err)
    24  	}
    25  
    26  	if srcAddrPort.Addr().Is4() {
    27  		if isGlobal {
    28  			key := &CtKey4Global{
    29  				TupleKey4Global: tuple.TupleKey4Global{
    30  					TupleKey4: tuple.TupleKey4{
    31  						SourcePort: uint16(srcAddrPort.Port()),
    32  						DestPort:   uint16(dstAddrPort.Port()),
    33  						NextHeader: proto,
    34  						Flags:      TUPLE_F_OUT,
    35  					},
    36  				},
    37  			}
    38  			// CTmap has the addresses in the reverse order w.r.t. the original direction
    39  			key.SourceAddr.FromAddr(dstAddrPort.Addr())
    40  			key.DestAddr.FromAddr(srcAddrPort.Addr())
    41  			if ingress {
    42  				key.Flags = TUPLE_F_IN
    43  			}
    44  			return key.ToNetwork(), true, nil
    45  		}
    46  
    47  		key := &CtKey4{
    48  			TupleKey4: tuple.TupleKey4{
    49  				SourcePort: uint16(srcAddrPort.Port()),
    50  				DestPort:   uint16(dstAddrPort.Port()),
    51  				NextHeader: proto,
    52  				Flags:      TUPLE_F_OUT,
    53  			},
    54  		}
    55  		// CTmap has the addresses in the reverse order w.r.t. the original direction
    56  		key.SourceAddr.FromAddr(dstAddrPort.Addr())
    57  		key.DestAddr.FromAddr(srcAddrPort.Addr())
    58  		if ingress {
    59  			key.Flags = TUPLE_F_IN
    60  		}
    61  		return key.ToNetwork(), true, nil
    62  	}
    63  
    64  	if isGlobal {
    65  		key := &CtKey6Global{
    66  			TupleKey6Global: tuple.TupleKey6Global{
    67  				TupleKey6: tuple.TupleKey6{
    68  					SourcePort: uint16(srcAddrPort.Port()),
    69  					DestPort:   uint16(dstAddrPort.Port()),
    70  					NextHeader: proto,
    71  					Flags:      TUPLE_F_OUT,
    72  				},
    73  			},
    74  		}
    75  		// CTmap has the addresses in the reverse order w.r.t. the original direction
    76  		key.SourceAddr.FromAddr(dstAddrPort.Addr())
    77  		key.DestAddr.FromAddr(srcAddrPort.Addr())
    78  		if ingress {
    79  			key.Flags = TUPLE_F_IN
    80  		}
    81  		return key.ToNetwork(), false, nil
    82  	}
    83  
    84  	key := &CtKey6{
    85  		TupleKey6: tuple.TupleKey6{
    86  			SourcePort: uint16(srcAddrPort.Port()),
    87  			DestPort:   uint16(dstAddrPort.Port()),
    88  			NextHeader: proto,
    89  			Flags:      TUPLE_F_OUT,
    90  		},
    91  	}
    92  	// CTmap has the addresses in the reverse order w.r.t. the original direction
    93  	key.SourceAddr.FromAddr(dstAddrPort.Addr())
    94  	key.DestAddr.FromAddr(srcAddrPort.Addr())
    95  	if ingress {
    96  		key.Flags = TUPLE_F_IN
    97  	}
    98  	return key.ToNetwork(), false, nil
    99  }
   100  
   101  func getMapName(mapname string, ipv4 bool, proto u8proto.U8proto) string {
   102  	if ipv4 {
   103  		if proto == u8proto.TCP {
   104  			mapname = MapNameTCP4 + mapname
   105  		} else {
   106  			mapname = MapNameAny4 + mapname
   107  		}
   108  	} else {
   109  		if proto == u8proto.TCP {
   110  			mapname = MapNameTCP6 + mapname
   111  		} else {
   112  			mapname = MapNameAny6 + mapname
   113  		}
   114  	}
   115  	return mapname
   116  }
   117  
   118  func getOrOpenMap(epname string, ipv4 bool, proto u8proto.U8proto) (*bpf.Map, error) {
   119  	mapname := getMapName(epname, ipv4, proto)
   120  	if m := bpf.GetMap(mapname); m != nil {
   121  		return m, nil
   122  	}
   123  
   124  	if epname == "global" {
   125  		if ipv4 {
   126  			return bpf.OpenMap(bpf.MapPath(mapname), &CtKey4Global{}, &CtEntry{})
   127  		}
   128  
   129  		return bpf.OpenMap(bpf.MapPath(mapname), &CtKey6Global{}, &CtEntry{})
   130  	}
   131  
   132  	if ipv4 {
   133  		return bpf.OpenMap(bpf.MapPath(mapname), &CtKey4{}, &CtEntry{})
   134  	}
   135  
   136  	return bpf.OpenMap(bpf.MapPath(mapname), &CtKey6{}, &CtEntry{})
   137  }
   138  
   139  // Lookup opens a conntrack map if necessary, and does a lookup on it with a key constructed from
   140  // the parameters
   141  // 'epname' is a 5-digit representation of the endpoint ID if local maps
   142  // are to be used, or "global" if global maps should be used.
   143  func Lookup(epname string, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool) (*CtEntry, error) {
   144  	isGlobal := epname == "global"
   145  
   146  	key, ipv4, err := createTupleKey(isGlobal, srcAddr, dstAddr, proto, ingress)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	m, err := getOrOpenMap(epname, ipv4, proto)
   152  	if err != nil || m == nil {
   153  		return nil, err
   154  	}
   155  
   156  	v, err := m.Lookup(key)
   157  	if err != nil || v == nil {
   158  		return nil, err
   159  	}
   160  
   161  	return v.(*CtEntry), err
   162  }
   163  
   164  // Update opens a conntrack map if necessary, and does a lookup on it with a key constructed from
   165  // the parameters, and updates the found entry (if any) via 'updateFn'.
   166  // 'epname' is a 5-digit representation of the endpoint ID if local maps
   167  // are to be used, or "global" if global maps should be used.
   168  func Update(epname string, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool,
   169  	updateFn func(*CtEntry) error) error {
   170  	isGlobal := epname == "global"
   171  
   172  	key, ipv4, err := createTupleKey(isGlobal, srcAddr, dstAddr, proto, ingress)
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	m, err := getOrOpenMap(epname, ipv4, proto)
   178  	if err != nil || m == nil {
   179  		return err
   180  	}
   181  
   182  	v, err := m.Lookup(key)
   183  	if err != nil || v == nil {
   184  		return err
   185  	}
   186  
   187  	entry := v.(*CtEntry)
   188  	err = updateFn(entry)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	return m.Update(key, entry)
   194  }
   195  
   196  func getMapWithName(epname string, ipv4 bool, proto u8proto.U8proto) *bpf.Map {
   197  	return bpf.GetMap(getMapName(epname, ipv4, proto))
   198  }
   199  
   200  // CloseLocalMaps closes all local conntrack maps opened previously
   201  // for lookup with the given 'mapname'.
   202  func CloseLocalMaps(mapname string) {
   203  	// only close local maps. Global map is kept open as long as cilium-agent is running.
   204  	if mapname != "global" {
   205  		// close IPv4 maps, if any
   206  		if m := getMapWithName(mapname, true, u8proto.TCP); m != nil {
   207  			m.Close()
   208  		}
   209  		if m := getMapWithName(mapname, true, u8proto.UDP); m != nil {
   210  			m.Close()
   211  		}
   212  
   213  		// close IPv6 maps, if any
   214  		if m := getMapWithName(mapname, false, u8proto.TCP); m != nil {
   215  			m.Close()
   216  		}
   217  		if m := getMapWithName(mapname, false, u8proto.UDP); m != nil {
   218  			m.Close()
   219  		}
   220  	}
   221  }