1package netlink 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/hex" 7 "errors" 8 "fmt" 9 "net" 10 "syscall" 11 12 "github.com/vishvananda/netlink/nl" 13 "golang.org/x/sys/unix" 14) 15 16// Constants used in TcU32Sel.Flags. 17const ( 18 TC_U32_TERMINAL = nl.TC_U32_TERMINAL 19 TC_U32_OFFSET = nl.TC_U32_OFFSET 20 TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET 21 TC_U32_EAT = nl.TC_U32_EAT 22) 23 24// Sel of the U32 filters that contains multiple TcU32Key. This is the type 25// alias and the frontend representation of nl.TcU32Sel. It is serialized into 26// canonical nl.TcU32Sel with the appropriate endianness. 27type TcU32Sel = nl.TcU32Sel 28 29// TcU32Key contained of Sel in the U32 filters. This is the type alias and the 30// frontend representation of nl.TcU32Key. It is serialized into chanonical 31// nl.TcU32Sel with the appropriate endianness. 32type TcU32Key = nl.TcU32Key 33 34// U32 filters on many packet related properties 35type U32 struct { 36 FilterAttrs 37 ClassId uint32 38 Divisor uint32 // Divisor MUST be power of 2. 39 Hash uint32 40 RedirIndex int 41 Sel *TcU32Sel 42 Actions []Action 43} 44 45func (filter *U32) Attrs() *FilterAttrs { 46 return &filter.FilterAttrs 47} 48 49func (filter *U32) Type() string { 50 return "u32" 51} 52 53// Fw filter filters on firewall marks 54// NOTE: this is in filter_linux because it refers to nl.TcPolice which 55// is defined in nl/tc_linux.go 56type Fw struct { 57 FilterAttrs 58 ClassId uint32 59 // TODO remove nl type from interface 60 Police nl.TcPolice 61 InDev string 62 // TODO Action 63 Mask uint32 64 AvRate uint32 65 Rtab [256]uint32 66 Ptab [256]uint32 67} 68 69func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { 70 var rtab [256]uint32 71 var ptab [256]uint32 72 rcellLog := -1 73 pcellLog := -1 74 avrate := fattrs.AvRate / 8 75 police := nl.TcPolice{} 76 police.Rate.Rate = fattrs.Rate / 8 77 police.PeakRate.Rate = fattrs.PeakRate / 8 78 buffer := fattrs.Buffer 79 linklayer := nl.LINKLAYER_ETHERNET 80 81 if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC { 82 linklayer = fattrs.LinkLayer 83 } 84 85 police.Action = int32(fattrs.Action) 86 if police.Rate.Rate != 0 { 87 police.Rate.Mpu = fattrs.Mpu 88 police.Rate.Overhead = fattrs.Overhead 89 if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 { 90 return nil, errors.New("TBF: failed to calculate rate table") 91 } 92 police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer))) 93 } 94 police.Mtu = fattrs.Mtu 95 if police.PeakRate.Rate != 0 { 96 police.PeakRate.Mpu = fattrs.Mpu 97 police.PeakRate.Overhead = fattrs.Overhead 98 if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 { 99 return nil, errors.New("POLICE: failed to calculate peak rate table") 100 } 101 } 102 103 return &Fw{ 104 FilterAttrs: attrs, 105 ClassId: fattrs.ClassId, 106 InDev: fattrs.InDev, 107 Mask: fattrs.Mask, 108 Police: police, 109 AvRate: avrate, 110 Rtab: rtab, 111 Ptab: ptab, 112 }, nil 113} 114 115func (filter *Fw) Attrs() *FilterAttrs { 116 return &filter.FilterAttrs 117} 118 119func (filter *Fw) Type() string { 120 return "fw" 121} 122 123// FilterDel will delete a filter from the system. 124// Equivalent to: `tc filter del $filter` 125func FilterDel(filter Filter) error { 126 return pkgHandle.FilterDel(filter) 127} 128 129// FilterDel will delete a filter from the system. 130// Equivalent to: `tc filter del $filter` 131func (h *Handle) FilterDel(filter Filter) error { 132 req := h.newNetlinkRequest(unix.RTM_DELTFILTER, unix.NLM_F_ACK) 133 base := filter.Attrs() 134 msg := &nl.TcMsg{ 135 Family: nl.FAMILY_ALL, 136 Ifindex: int32(base.LinkIndex), 137 Handle: base.Handle, 138 Parent: base.Parent, 139 Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), 140 } 141 req.AddData(msg) 142 143 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 144 return err 145} 146 147// FilterAdd will add a filter to the system. 148// Equivalent to: `tc filter add $filter` 149func FilterAdd(filter Filter) error { 150 return pkgHandle.FilterAdd(filter) 151} 152 153// FilterAdd will add a filter to the system. 154// Equivalent to: `tc filter add $filter` 155func (h *Handle) FilterAdd(filter Filter) error { 156 return h.filterModify(filter, unix.NLM_F_CREATE|unix.NLM_F_EXCL) 157} 158 159// FilterReplace will replace a filter. 160// Equivalent to: `tc filter replace $filter` 161func FilterReplace(filter Filter) error { 162 return pkgHandle.FilterReplace(filter) 163} 164 165// FilterReplace will replace a filter. 166// Equivalent to: `tc filter replace $filter` 167func (h *Handle) FilterReplace(filter Filter) error { 168 return h.filterModify(filter, unix.NLM_F_CREATE) 169} 170 171func (h *Handle) filterModify(filter Filter, flags int) error { 172 native = nl.NativeEndian() 173 req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK) 174 base := filter.Attrs() 175 msg := &nl.TcMsg{ 176 Family: nl.FAMILY_ALL, 177 Ifindex: int32(base.LinkIndex), 178 Handle: base.Handle, 179 Parent: base.Parent, 180 Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)), 181 } 182 req.AddData(msg) 183 req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type()))) 184 185 options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) 186 187 switch filter := filter.(type) { 188 case *U32: 189 sel := filter.Sel 190 if sel == nil { 191 // match all 192 sel = &nl.TcU32Sel{ 193 Nkeys: 1, 194 Flags: nl.TC_U32_TERMINAL, 195 } 196 sel.Keys = append(sel.Keys, nl.TcU32Key{}) 197 } 198 199 if native != networkOrder { 200 // Copy TcU32Sel. 201 cSel := *sel 202 keys := make([]nl.TcU32Key, cap(sel.Keys)) 203 copy(keys, sel.Keys) 204 cSel.Keys = keys 205 sel = &cSel 206 207 // Handle the endianness of attributes 208 sel.Offmask = native.Uint16(htons(sel.Offmask)) 209 sel.Hmask = native.Uint32(htonl(sel.Hmask)) 210 for i, key := range sel.Keys { 211 sel.Keys[i].Mask = native.Uint32(htonl(key.Mask)) 212 sel.Keys[i].Val = native.Uint32(htonl(key.Val)) 213 } 214 } 215 sel.Nkeys = uint8(len(sel.Keys)) 216 options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize()) 217 if filter.ClassId != 0 { 218 options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId)) 219 } 220 if filter.Divisor != 0 { 221 if (filter.Divisor-1)&filter.Divisor != 0 { 222 return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor) 223 } 224 options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor)) 225 } 226 if filter.Hash != 0 { 227 options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash)) 228 } 229 actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil) 230 // backwards compatibility 231 if filter.RedirIndex != 0 { 232 filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...) 233 } 234 if err := EncodeActions(actionsAttr, filter.Actions); err != nil { 235 return err 236 } 237 case *Fw: 238 if filter.Mask != 0 { 239 b := make([]byte, 4) 240 native.PutUint32(b, filter.Mask) 241 options.AddRtAttr(nl.TCA_FW_MASK, b) 242 } 243 if filter.InDev != "" { 244 options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev)) 245 } 246 if (filter.Police != nl.TcPolice{}) { 247 248 police := options.AddRtAttr(nl.TCA_FW_POLICE, nil) 249 police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize()) 250 if (filter.Police.Rate != nl.TcRateSpec{}) { 251 payload := SerializeRtab(filter.Rtab) 252 police.AddRtAttr(nl.TCA_POLICE_RATE, payload) 253 } 254 if (filter.Police.PeakRate != nl.TcRateSpec{}) { 255 payload := SerializeRtab(filter.Ptab) 256 police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload) 257 } 258 } 259 if filter.ClassId != 0 { 260 b := make([]byte, 4) 261 native.PutUint32(b, filter.ClassId) 262 options.AddRtAttr(nl.TCA_FW_CLASSID, b) 263 } 264 case *BpfFilter: 265 var bpfFlags uint32 266 if filter.ClassId != 0 { 267 options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId)) 268 } 269 if filter.Fd >= 0 { 270 options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd)))) 271 } 272 if filter.Name != "" { 273 options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name)) 274 } 275 if filter.DirectAction { 276 bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT 277 } 278 options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) 279 case *MatchAll: 280 actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil) 281 if err := EncodeActions(actionsAttr, filter.Actions); err != nil { 282 return err 283 } 284 if filter.ClassId != 0 { 285 options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId)) 286 } 287 } 288 289 req.AddData(options) 290 _, err := req.Execute(unix.NETLINK_ROUTE, 0) 291 return err 292} 293 294// FilterList gets a list of filters in the system. 295// Equivalent to: `tc filter show`. 296// Generally returns nothing if link and parent are not specified. 297func FilterList(link Link, parent uint32) ([]Filter, error) { 298 return pkgHandle.FilterList(link, parent) 299} 300 301// FilterList gets a list of filters in the system. 302// Equivalent to: `tc filter show`. 303// Generally returns nothing if link and parent are not specified. 304func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { 305 req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP) 306 msg := &nl.TcMsg{ 307 Family: nl.FAMILY_ALL, 308 Parent: parent, 309 } 310 if link != nil { 311 base := link.Attrs() 312 h.ensureIndex(base) 313 msg.Ifindex = int32(base.Index) 314 } 315 req.AddData(msg) 316 317 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER) 318 if err != nil { 319 return nil, err 320 } 321 322 var res []Filter 323 for _, m := range msgs { 324 msg := nl.DeserializeTcMsg(m) 325 326 attrs, err := nl.ParseRouteAttr(m[msg.Len():]) 327 if err != nil { 328 return nil, err 329 } 330 331 base := FilterAttrs{ 332 LinkIndex: int(msg.Ifindex), 333 Handle: msg.Handle, 334 Parent: msg.Parent, 335 } 336 base.Priority, base.Protocol = MajorMinor(msg.Info) 337 base.Protocol = nl.Swap16(base.Protocol) 338 339 var filter Filter 340 filterType := "" 341 detailed := false 342 for _, attr := range attrs { 343 switch attr.Attr.Type { 344 case nl.TCA_KIND: 345 filterType = string(attr.Value[:len(attr.Value)-1]) 346 switch filterType { 347 case "u32": 348 filter = &U32{} 349 case "fw": 350 filter = &Fw{} 351 case "bpf": 352 filter = &BpfFilter{} 353 case "matchall": 354 filter = &MatchAll{} 355 default: 356 filter = &GenericFilter{FilterType: filterType} 357 } 358 case nl.TCA_OPTIONS: 359 data, err := nl.ParseRouteAttr(attr.Value) 360 if err != nil { 361 return nil, err 362 } 363 switch filterType { 364 case "u32": 365 detailed, err = parseU32Data(filter, data) 366 if err != nil { 367 return nil, err 368 } 369 case "fw": 370 detailed, err = parseFwData(filter, data) 371 if err != nil { 372 return nil, err 373 } 374 case "bpf": 375 detailed, err = parseBpfData(filter, data) 376 if err != nil { 377 return nil, err 378 } 379 case "matchall": 380 detailed, err = parseMatchAllData(filter, data) 381 if err != nil { 382 return nil, err 383 } 384 default: 385 detailed = true 386 } 387 } 388 } 389 // only return the detailed version of the filter 390 if detailed { 391 *filter.Attrs() = base 392 res = append(res, filter) 393 } 394 } 395 396 return res, nil 397} 398 399func toTcGen(attrs *ActionAttrs, tcgen *nl.TcGen) { 400 tcgen.Index = uint32(attrs.Index) 401 tcgen.Capab = uint32(attrs.Capab) 402 tcgen.Action = int32(attrs.Action) 403 tcgen.Refcnt = int32(attrs.Refcnt) 404 tcgen.Bindcnt = int32(attrs.Bindcnt) 405} 406 407func toAttrs(tcgen *nl.TcGen, attrs *ActionAttrs) { 408 attrs.Index = int(tcgen.Index) 409 attrs.Capab = int(tcgen.Capab) 410 attrs.Action = TcAct(tcgen.Action) 411 attrs.Refcnt = int(tcgen.Refcnt) 412 attrs.Bindcnt = int(tcgen.Bindcnt) 413} 414 415func EncodeActions(attr *nl.RtAttr, actions []Action) error { 416 tabIndex := int(nl.TCA_ACT_TAB) 417 418 for _, action := range actions { 419 switch action := action.(type) { 420 default: 421 return fmt.Errorf("unknown action type %s", action.Type()) 422 case *MirredAction: 423 table := attr.AddRtAttr(tabIndex, nil) 424 tabIndex++ 425 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred")) 426 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 427 mirred := nl.TcMirred{ 428 Eaction: int32(action.MirredAction), 429 Ifindex: uint32(action.Ifindex), 430 } 431 toTcGen(action.Attrs(), &mirred.TcGen) 432 aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize()) 433 case *TunnelKeyAction: 434 table := attr.AddRtAttr(tabIndex, nil) 435 tabIndex++ 436 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("tunnel_key")) 437 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 438 tun := nl.TcTunnelKey{ 439 Action: int32(action.Action), 440 } 441 toTcGen(action.Attrs(), &tun.TcGen) 442 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_PARMS, tun.Serialize()) 443 if action.Action == TCA_TUNNEL_KEY_SET { 444 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_KEY_ID, htonl(action.KeyID)) 445 if v4 := action.SrcAddr.To4(); v4 != nil { 446 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC, v4[:]) 447 } else if v6 := action.SrcAddr.To16(); v6 != nil { 448 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, v6[:]) 449 } else { 450 return fmt.Errorf("invalid src addr %s for tunnel_key action", action.SrcAddr) 451 } 452 if v4 := action.DstAddr.To4(); v4 != nil { 453 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_DST, v4[:]) 454 } else if v6 := action.DstAddr.To16(); v6 != nil { 455 aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, v6[:]) 456 } else { 457 return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr) 458 } 459 } 460 case *SkbEditAction: 461 table := attr.AddRtAttr(tabIndex, nil) 462 tabIndex++ 463 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit")) 464 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 465 skbedit := nl.TcSkbEdit{} 466 toTcGen(action.Attrs(), &skbedit.TcGen) 467 aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize()) 468 if action.QueueMapping != nil { 469 aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping)) 470 } 471 if action.Priority != nil { 472 aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority)) 473 } 474 if action.PType != nil { 475 aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType)) 476 } 477 if action.Mark != nil { 478 aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark)) 479 } 480 case *ConnmarkAction: 481 table := attr.AddRtAttr(tabIndex, nil) 482 tabIndex++ 483 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("connmark")) 484 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 485 connmark := nl.TcConnmark{ 486 Zone: action.Zone, 487 } 488 toTcGen(action.Attrs(), &connmark.TcGen) 489 aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize()) 490 case *BpfAction: 491 table := attr.AddRtAttr(tabIndex, nil) 492 tabIndex++ 493 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf")) 494 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 495 gen := nl.TcGen{} 496 toTcGen(action.Attrs(), &gen) 497 aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize()) 498 aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd))) 499 aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name)) 500 case *GenericAction: 501 table := attr.AddRtAttr(tabIndex, nil) 502 tabIndex++ 503 table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact")) 504 aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) 505 gen := nl.TcGen{} 506 toTcGen(action.Attrs(), &gen) 507 aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize()) 508 } 509 } 510 return nil 511} 512 513func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { 514 var actions []Action 515 for _, table := range tables { 516 var action Action 517 var actionType string 518 aattrs, err := nl.ParseRouteAttr(table.Value) 519 if err != nil { 520 return nil, err 521 } 522 nextattr: 523 for _, aattr := range aattrs { 524 switch aattr.Attr.Type { 525 case nl.TCA_KIND: 526 actionType = string(aattr.Value[:len(aattr.Value)-1]) 527 // only parse if the action is mirred or bpf 528 switch actionType { 529 case "mirred": 530 action = &MirredAction{} 531 case "bpf": 532 action = &BpfAction{} 533 case "connmark": 534 action = &ConnmarkAction{} 535 case "gact": 536 action = &GenericAction{} 537 case "tunnel_key": 538 action = &TunnelKeyAction{} 539 case "skbedit": 540 action = &SkbEditAction{} 541 default: 542 break nextattr 543 } 544 case nl.TCA_OPTIONS: 545 adata, err := nl.ParseRouteAttr(aattr.Value) 546 if err != nil { 547 return nil, err 548 } 549 for _, adatum := range adata { 550 switch actionType { 551 case "mirred": 552 switch adatum.Attr.Type { 553 case nl.TCA_MIRRED_PARMS: 554 mirred := *nl.DeserializeTcMirred(adatum.Value) 555 action.(*MirredAction).ActionAttrs = ActionAttrs{} 556 toAttrs(&mirred.TcGen, action.Attrs()) 557 action.(*MirredAction).Ifindex = int(mirred.Ifindex) 558 action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction) 559 } 560 case "tunnel_key": 561 switch adatum.Attr.Type { 562 case nl.TCA_TUNNEL_KEY_PARMS: 563 tun := *nl.DeserializeTunnelKey(adatum.Value) 564 action.(*TunnelKeyAction).ActionAttrs = ActionAttrs{} 565 toAttrs(&tun.TcGen, action.Attrs()) 566 action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action) 567 case nl.TCA_TUNNEL_KEY_ENC_KEY_ID: 568 action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4]) 569 case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC: 570 case nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC: 571 action.(*TunnelKeyAction).SrcAddr = net.IP(adatum.Value[:]) 572 case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST: 573 case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST: 574 action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:]) 575 } 576 case "skbedit": 577 switch adatum.Attr.Type { 578 case nl.TCA_SKBEDIT_PARMS: 579 skbedit := *nl.DeserializeSkbEdit(adatum.Value) 580 action.(*SkbEditAction).ActionAttrs = ActionAttrs{} 581 toAttrs(&skbedit.TcGen, action.Attrs()) 582 case nl.TCA_SKBEDIT_MARK: 583 mark := native.Uint32(adatum.Value[0:4]) 584 action.(*SkbEditAction).Mark = &mark 585 case nl.TCA_SKBEDIT_PRIORITY: 586 priority := native.Uint32(adatum.Value[0:4]) 587 action.(*SkbEditAction).Priority = &priority 588 case nl.TCA_SKBEDIT_PTYPE: 589 ptype := native.Uint16(adatum.Value[0:2]) 590 action.(*SkbEditAction).PType = &ptype 591 case nl.TCA_SKBEDIT_QUEUE_MAPPING: 592 mapping := native.Uint16(adatum.Value[0:2]) 593 action.(*SkbEditAction).QueueMapping = &mapping 594 } 595 case "bpf": 596 switch adatum.Attr.Type { 597 case nl.TCA_ACT_BPF_PARMS: 598 gen := *nl.DeserializeTcGen(adatum.Value) 599 toAttrs(&gen, action.Attrs()) 600 case nl.TCA_ACT_BPF_FD: 601 action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4])) 602 case nl.TCA_ACT_BPF_NAME: 603 action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1]) 604 } 605 case "connmark": 606 switch adatum.Attr.Type { 607 case nl.TCA_CONNMARK_PARMS: 608 connmark := *nl.DeserializeTcConnmark(adatum.Value) 609 action.(*ConnmarkAction).ActionAttrs = ActionAttrs{} 610 toAttrs(&connmark.TcGen, action.Attrs()) 611 action.(*ConnmarkAction).Zone = connmark.Zone 612 } 613 case "gact": 614 switch adatum.Attr.Type { 615 case nl.TCA_GACT_PARMS: 616 gen := *nl.DeserializeTcGen(adatum.Value) 617 toAttrs(&gen, action.Attrs()) 618 } 619 } 620 } 621 } 622 } 623 actions = append(actions, action) 624 } 625 return actions, nil 626} 627 628func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { 629 native = nl.NativeEndian() 630 u32 := filter.(*U32) 631 detailed := false 632 for _, datum := range data { 633 switch datum.Attr.Type { 634 case nl.TCA_U32_SEL: 635 detailed = true 636 sel := nl.DeserializeTcU32Sel(datum.Value) 637 u32.Sel = sel 638 if native != networkOrder { 639 // Handle the endianness of attributes 640 u32.Sel.Offmask = native.Uint16(htons(sel.Offmask)) 641 u32.Sel.Hmask = native.Uint32(htonl(sel.Hmask)) 642 for i, key := range u32.Sel.Keys { 643 u32.Sel.Keys[i].Mask = native.Uint32(htonl(key.Mask)) 644 u32.Sel.Keys[i].Val = native.Uint32(htonl(key.Val)) 645 } 646 } 647 case nl.TCA_U32_ACT: 648 tables, err := nl.ParseRouteAttr(datum.Value) 649 if err != nil { 650 return detailed, err 651 } 652 u32.Actions, err = parseActions(tables) 653 if err != nil { 654 return detailed, err 655 } 656 for _, action := range u32.Actions { 657 if action, ok := action.(*MirredAction); ok { 658 u32.RedirIndex = int(action.Ifindex) 659 } 660 } 661 case nl.TCA_U32_CLASSID: 662 u32.ClassId = native.Uint32(datum.Value) 663 case nl.TCA_U32_DIVISOR: 664 u32.Divisor = native.Uint32(datum.Value) 665 case nl.TCA_U32_HASH: 666 u32.Hash = native.Uint32(datum.Value) 667 } 668 } 669 return detailed, nil 670} 671 672func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { 673 native = nl.NativeEndian() 674 fw := filter.(*Fw) 675 detailed := true 676 for _, datum := range data { 677 switch datum.Attr.Type { 678 case nl.TCA_FW_MASK: 679 fw.Mask = native.Uint32(datum.Value[0:4]) 680 case nl.TCA_FW_CLASSID: 681 fw.ClassId = native.Uint32(datum.Value[0:4]) 682 case nl.TCA_FW_INDEV: 683 fw.InDev = string(datum.Value[:len(datum.Value)-1]) 684 case nl.TCA_FW_POLICE: 685 adata, _ := nl.ParseRouteAttr(datum.Value) 686 for _, aattr := range adata { 687 switch aattr.Attr.Type { 688 case nl.TCA_POLICE_TBF: 689 fw.Police = *nl.DeserializeTcPolice(aattr.Value) 690 case nl.TCA_POLICE_RATE: 691 fw.Rtab = DeserializeRtab(aattr.Value) 692 case nl.TCA_POLICE_PEAKRATE: 693 fw.Ptab = DeserializeRtab(aattr.Value) 694 } 695 } 696 } 697 } 698 return detailed, nil 699} 700 701func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { 702 native = nl.NativeEndian() 703 bpf := filter.(*BpfFilter) 704 detailed := true 705 for _, datum := range data { 706 switch datum.Attr.Type { 707 case nl.TCA_BPF_FD: 708 bpf.Fd = int(native.Uint32(datum.Value[0:4])) 709 case nl.TCA_BPF_NAME: 710 bpf.Name = string(datum.Value[:len(datum.Value)-1]) 711 case nl.TCA_BPF_CLASSID: 712 bpf.ClassId = native.Uint32(datum.Value[0:4]) 713 case nl.TCA_BPF_FLAGS: 714 flags := native.Uint32(datum.Value[0:4]) 715 if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 { 716 bpf.DirectAction = true 717 } 718 case nl.TCA_BPF_ID: 719 bpf.Id = int(native.Uint32(datum.Value[0:4])) 720 case nl.TCA_BPF_TAG: 721 bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1]) 722 } 723 } 724 return detailed, nil 725} 726 727func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { 728 native = nl.NativeEndian() 729 matchall := filter.(*MatchAll) 730 detailed := true 731 for _, datum := range data { 732 switch datum.Attr.Type { 733 case nl.TCA_MATCHALL_CLASSID: 734 matchall.ClassId = native.Uint32(datum.Value[0:4]) 735 case nl.TCA_MATCHALL_ACT: 736 tables, err := nl.ParseRouteAttr(datum.Value) 737 if err != nil { 738 return detailed, err 739 } 740 matchall.Actions, err = parseActions(tables) 741 if err != nil { 742 return detailed, err 743 } 744 } 745 } 746 return detailed, nil 747} 748 749func AlignToAtm(size uint) uint { 750 var linksize, cells int 751 cells = int(size / nl.ATM_CELL_PAYLOAD) 752 if (size % nl.ATM_CELL_PAYLOAD) > 0 { 753 cells++ 754 } 755 linksize = cells * nl.ATM_CELL_SIZE 756 return uint(linksize) 757} 758 759func AdjustSize(sz uint, mpu uint, linklayer int) uint { 760 if sz < mpu { 761 sz = mpu 762 } 763 switch linklayer { 764 case nl.LINKLAYER_ATM: 765 return AlignToAtm(sz) 766 default: 767 return sz 768 } 769} 770 771func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, linklayer int) int { 772 bps := rate.Rate 773 mpu := rate.Mpu 774 var sz uint 775 if mtu == 0 { 776 mtu = 2047 777 } 778 if cellLog < 0 { 779 cellLog = 0 780 for (mtu >> uint(cellLog)) > 255 { 781 cellLog++ 782 } 783 } 784 for i := 0; i < 256; i++ { 785 sz = AdjustSize(uint((i+1)<<uint32(cellLog)), uint(mpu), linklayer) 786 rtab[i] = uint32(Xmittime(uint64(bps), uint32(sz))) 787 } 788 rate.CellAlign = -1 789 rate.CellLog = uint8(cellLog) 790 rate.Linklayer = uint8(linklayer & nl.TC_LINKLAYER_MASK) 791 return cellLog 792} 793 794func DeserializeRtab(b []byte) [256]uint32 { 795 var rtab [256]uint32 796 native := nl.NativeEndian() 797 r := bytes.NewReader(b) 798 _ = binary.Read(r, native, &rtab) 799 return rtab 800} 801 802func SerializeRtab(rtab [256]uint32) []byte { 803 native := nl.NativeEndian() 804 var w bytes.Buffer 805 _ = binary.Write(&w, native, rtab) 806 return w.Bytes() 807} 808