github.com/vishvananda/netlink@v1.3.1/gtp_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"strings"
     8  	"syscall"
     9  
    10  	"github.com/vishvananda/netlink/nl"
    11  	"golang.org/x/sys/unix"
    12  )
    13  
    14  type PDP struct {
    15  	Version     uint32
    16  	TID         uint64
    17  	PeerAddress net.IP
    18  	MSAddress   net.IP
    19  	Flow        uint16
    20  	NetNSFD     uint32
    21  	ITEI        uint32
    22  	OTEI        uint32
    23  }
    24  
    25  func (pdp *PDP) String() string {
    26  	elems := []string{}
    27  	elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version))
    28  	if pdp.Version == 0 {
    29  		elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID))
    30  	} else if pdp.Version == 1 {
    31  		elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI))
    32  	}
    33  	elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress))
    34  	elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress))
    35  	return fmt.Sprintf("{%s}", strings.Join(elems, " "))
    36  }
    37  
    38  func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
    39  	for _, a := range attrs {
    40  		switch a.Attr.Type {
    41  		case nl.GENL_GTP_ATTR_VERSION:
    42  			p.Version = native.Uint32(a.Value)
    43  		case nl.GENL_GTP_ATTR_TID:
    44  			p.TID = native.Uint64(a.Value)
    45  		case nl.GENL_GTP_ATTR_PEER_ADDRESS:
    46  			p.PeerAddress = net.IP(a.Value)
    47  		case nl.GENL_GTP_ATTR_MS_ADDRESS:
    48  			p.MSAddress = net.IP(a.Value)
    49  		case nl.GENL_GTP_ATTR_FLOW:
    50  			p.Flow = native.Uint16(a.Value)
    51  		case nl.GENL_GTP_ATTR_NET_NS_FD:
    52  			p.NetNSFD = native.Uint32(a.Value)
    53  		case nl.GENL_GTP_ATTR_I_TEI:
    54  			p.ITEI = native.Uint32(a.Value)
    55  		case nl.GENL_GTP_ATTR_O_TEI:
    56  			p.OTEI = native.Uint32(a.Value)
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  func parsePDP(msgs [][]byte) ([]*PDP, error) {
    63  	pdps := make([]*PDP, 0, len(msgs))
    64  	for _, m := range msgs {
    65  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  		pdp := &PDP{}
    70  		if err := pdp.parseAttributes(attrs); err != nil {
    71  			return nil, err
    72  		}
    73  		pdps = append(pdps, pdp)
    74  	}
    75  	return pdps, nil
    76  }
    77  
    78  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
    79  // or incomplete.
    80  func (h *Handle) GTPPDPList() ([]*PDP, error) {
    81  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	msg := &nl.Genlmsg{
    86  		Command: nl.GENL_GTP_CMD_GETPDP,
    87  		Version: nl.GENL_GTP_VERSION,
    88  	}
    89  	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
    90  	req.AddData(msg)
    91  	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
    92  	if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
    93  		return nil, executeErr
    94  	}
    95  	pdps, err := parsePDP(msgs)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	return pdps, executeErr
   100  }
   101  
   102  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   103  // or incomplete.
   104  func GTPPDPList() ([]*PDP, error) {
   105  	return pkgHandle.GTPPDPList()
   106  }
   107  
   108  func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
   109  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	pdps, err := parsePDP(msgs)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	if len(pdps) != 1 {
   118  		return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP")
   119  	}
   120  	return pdps[0], nil
   121  }
   122  
   123  func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) {
   124  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	msg := &nl.Genlmsg{
   129  		Command: nl.GENL_GTP_CMD_GETPDP,
   130  		Version: nl.GENL_GTP_VERSION,
   131  	}
   132  	req := h.newNetlinkRequest(int(f.ID), 0)
   133  	req.AddData(msg)
   134  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
   135  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
   136  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid))))
   137  	return gtpPDPGet(req)
   138  }
   139  
   140  func GTPPDPByTID(link Link, tid int) (*PDP, error) {
   141  	return pkgHandle.GTPPDPByTID(link, tid)
   142  }
   143  
   144  func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) {
   145  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	msg := &nl.Genlmsg{
   150  		Command: nl.GENL_GTP_CMD_GETPDP,
   151  		Version: nl.GENL_GTP_VERSION,
   152  	}
   153  	req := h.newNetlinkRequest(int(f.ID), 0)
   154  	req.AddData(msg)
   155  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1)))
   156  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
   157  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei))))
   158  	return gtpPDPGet(req)
   159  }
   160  
   161  func GTPPDPByITEI(link Link, itei int) (*PDP, error) {
   162  	return pkgHandle.GTPPDPByITEI(link, itei)
   163  }
   164  
   165  func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
   166  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	msg := &nl.Genlmsg{
   171  		Command: nl.GENL_GTP_CMD_GETPDP,
   172  		Version: nl.GENL_GTP_VERSION,
   173  	}
   174  	req := h.newNetlinkRequest(int(f.ID), 0)
   175  	req.AddData(msg)
   176  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
   177  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
   178  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4())))
   179  	return gtpPDPGet(req)
   180  }
   181  
   182  func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
   183  	return pkgHandle.GTPPDPByMSAddress(link, addr)
   184  }
   185  
   186  func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
   187  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	msg := &nl.Genlmsg{
   192  		Command: nl.GENL_GTP_CMD_NEWPDP,
   193  		Version: nl.GENL_GTP_VERSION,
   194  	}
   195  	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
   196  	req.AddData(msg)
   197  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
   198  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
   199  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4())))
   200  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4())))
   201  
   202  	switch pdp.Version {
   203  	case 0:
   204  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
   205  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow)))
   206  	case 1:
   207  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
   208  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI)))
   209  	default:
   210  		return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
   211  	}
   212  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   213  	return err
   214  }
   215  
   216  func GTPPDPAdd(link Link, pdp *PDP) error {
   217  	return pkgHandle.GTPPDPAdd(link, pdp)
   218  }
   219  
   220  func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
   221  	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	msg := &nl.Genlmsg{
   226  		Command: nl.GENL_GTP_CMD_DELPDP,
   227  		Version: nl.GENL_GTP_VERSION,
   228  	}
   229  	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
   230  	req.AddData(msg)
   231  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
   232  	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
   233  
   234  	switch pdp.Version {
   235  	case 0:
   236  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
   237  	case 1:
   238  		req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
   239  	default:
   240  		return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
   241  	}
   242  	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
   243  	return err
   244  }
   245  
   246  func GTPPDPDel(link Link, pdp *PDP) error {
   247  	return pkgHandle.GTPPDPDel(link, pdp)
   248  }