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