github.com/osrg/gobgp/v3@v3.30.0/pkg/zebra/zapi_test.go (about) 1 // Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package zebra 17 18 import ( 19 "encoding/binary" 20 "net" 21 "syscall" 22 "testing" 23 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func Test_Header(t *testing.T) { 29 assert := assert.New(t) 30 31 command := map[uint8]APIType{ 32 2: zapi3IPv4RouteAdd, 33 3: zapi3IPv4RouteAdd, 34 4: zapi4IPv4RouteAdd, 35 5: zapi6Frr7RouteAdd, 36 6: zapi6Frr7RouteAdd, 37 } 38 for v := MinZapiVer; v <= MaxZapiVer; v++ { 39 //decodeFromBytes 40 buf := make([]byte, HeaderSize(v)) 41 binary.BigEndian.PutUint16(buf[0:], HeaderSize(v)) 42 buf[2] = headerMarker 43 if v >= 4 { 44 buf[2] = frrHeaderMarker 45 } 46 buf[3] = v 47 switch v { 48 case 2: 49 binary.BigEndian.PutUint16(buf[4:], uint16(command[v])) 50 case 3, 4: 51 binary.BigEndian.PutUint16(buf[4:], uint16(0)) // vrf id 52 binary.BigEndian.PutUint16(buf[6:], uint16(command[v])) 53 case 5, 6: 54 binary.BigEndian.PutUint32(buf[4:], uint32(0)) // vrf id 55 binary.BigEndian.PutUint16(buf[8:], uint16(command[v])) 56 } 57 h := &Header{} 58 err := h.decodeFromBytes(buf) 59 assert.Equal(nil, err) 60 61 //serialize 62 buf, err = h.serialize() 63 assert.Equal(nil, err) 64 h2 := &Header{} 65 err = h2.decodeFromBytes(buf) 66 assert.Equal(nil, err) 67 assert.Equal(h, h2) 68 69 // header_size mismatch 70 buf = make([]byte, HeaderSize(v)-1) // mismatch value 71 binary.BigEndian.PutUint16(buf[0:], HeaderSize(v)) 72 buf[2] = headerMarker 73 if v >= 4 { 74 buf[2] = frrHeaderMarker 75 } 76 buf[3] = v 77 h3 := &Header{} 78 err = h3.decodeFromBytes(buf) 79 assert.NotEqual(nil, err, "err should be nil") 80 } 81 } 82 83 func Test_interfaceUpdateBody(t *testing.T) { 84 assert := assert.New(t) 85 86 addSize := map[uint8]uint8{2: 39, 3: 44, 4: 50, 5: 50, 6: 54} 87 for v := MinZapiVer; v <= MaxZapiVer; v++ { 88 //decodeFromBytes 89 buf := make([]byte, interfaceNameSize+addSize[v]) 90 pos := interfaceNameSize 91 binary.BigEndian.PutUint32(buf[pos:], 1) //Index 92 pos += 4 93 buf[pos] = byte(interfaceActive) //Status 94 pos++ 95 binary.BigEndian.PutUint64(buf[pos:], 1) 96 pos += 8 // flags 97 if v > 3 { 98 buf[pos] = byte(ptmEnableOff) // ptm enable 99 pos++ 100 buf[pos] = byte(ptmStatusUnknown) // ptm status 101 pos++ 102 } 103 binary.BigEndian.PutUint32(buf[pos:], 1) 104 pos += 4 // metric 105 if v > 3 { 106 binary.BigEndian.PutUint32(buf[pos:], 10000) 107 pos += 4 // speed 108 } 109 binary.BigEndian.PutUint32(buf[pos:], 1500) 110 pos += 4 // MTU 111 binary.BigEndian.PutUint32(buf[pos:], 1500) 112 pos += 4 // MTU6 113 binary.BigEndian.PutUint32(buf[pos:], 200) 114 pos += 4 // bandwidth 115 if v == 6 { // "frr7.2", "" 116 binary.BigEndian.PutUint32(buf[pos:], 1) 117 pos += 4 // link Ifindex 118 } 119 if v > 2 { 120 binary.BigEndian.PutUint32(buf[pos:], uint32(linkTypeEther)) 121 pos += 4 // Linktype 122 } 123 binary.BigEndian.PutUint32(buf[pos:], 6) 124 pos += 4 // hwaddr_len 125 mac, _ := net.ParseMAC("01:23:45:67:89:ab") 126 copy(buf[pos:pos+6], []byte(mac)) 127 pos += 6 128 if v > 2 { 129 buf[pos] = byte(0) // link param 130 pos++ 131 } 132 b := &interfaceUpdateBody{} 133 software := NewSoftware(v, "") 134 err := b.decodeFromBytes(buf, v, software) 135 assert.Equal(nil, err) 136 assert.Equal("01:23:45:67:89:ab", b.hardwareAddr.String()) 137 buf = make([]byte, interfaceNameSize+32) //size mismatch 138 b = &interfaceUpdateBody{} 139 err = b.decodeFromBytes(buf, v, software) 140 assert.NotEqual(nil, err) 141 } 142 } 143 144 func Test_interfaceAddressUpdateBody(t *testing.T) { 145 assert := assert.New(t) 146 147 for v := MinZapiVer; v <= MaxZapiVer; v++ { 148 //decodeFromBytes 149 buf := make([]byte, 15) 150 pos := 0 151 binary.BigEndian.PutUint32(buf[pos:], 0) // index 152 pos += 4 153 buf[pos] = 0x01 // flags 154 pos++ 155 buf[pos] = 0x2 // family 156 pos++ 157 ip := net.ParseIP("192.168.100.1").To4() // prefix 158 copy(buf[pos:pos+4], []byte(ip)) 159 pos += 4 160 buf[pos] = byte(24) // prefix len 161 pos++ 162 dst := net.ParseIP("192.168.100.255").To4() // destination 163 copy(buf[pos:pos+4], []byte(dst)) 164 165 b := &interfaceAddressUpdateBody{} 166 software := NewSoftware(v, "") 167 err := b.decodeFromBytes(buf, v, software) 168 require.NoError(t, err) 169 170 assert.Equal(uint32(0), b.index) 171 assert.Equal(interfaceAddressFlag(1), b.flags) 172 assert.Equal("192.168.100.1", b.prefix.String()) 173 assert.Equal(uint8(24), b.length) 174 assert.Equal("192.168.100.255", b.destination.String()) 175 176 // af invalid 177 buf[5] = 0x4 178 pos++ 179 b = &interfaceAddressUpdateBody{} 180 err = b.decodeFromBytes(buf, v, software) 181 assert.NotEqual(nil, err) 182 } 183 } 184 185 func Test_routerIDUpdateBody(t *testing.T) { 186 assert := assert.New(t) 187 188 for v := MinZapiVer; v <= MaxZapiVer; v++ { 189 //decodeFromBytes 190 buf := make([]byte, 6) 191 pos := 0 192 buf[pos] = 0x2 193 pos++ 194 ip := net.ParseIP("192.168.100.1").To4() 195 copy(buf[pos:pos+4], []byte(ip)) 196 pos += 4 197 buf[pos] = byte(32) 198 199 b := &routerIDUpdateBody{} 200 software := NewSoftware(v, "") 201 err := b.decodeFromBytes(buf, v, software) 202 assert.Equal(nil, err) 203 assert.Equal("192.168.100.1", b.prefix.String()) 204 assert.Equal(uint8(32), b.length) 205 206 // af invalid 207 buf[0] = 0x4 208 pos++ 209 b = &routerIDUpdateBody{} 210 err = b.decodeFromBytes(buf, v, software) 211 assert.NotEqual(nil, err) 212 } 213 } 214 215 func Test_IPRouteBody_IPv4(t *testing.T) { 216 assert := assert.New(t) 217 218 size := map[uint8]uint8{2: 26, 3: 26, 4: 31, 5: 38, 6: 42} 219 command := map[uint8]APIType{ 220 2: zapi3IPv4RouteAdd, 221 3: zapi3IPv4RouteAdd, 222 4: zapi4IPv4RouteAdd, 223 5: zapi6Frr7RouteAdd, 224 6: RouteAdd, 225 } 226 routeType := routeConnect 227 message := map[uint8]MessageFlag{ 228 2: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi3MessageMTU, 229 3: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi3MessageMTU, 230 4: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi4MessageMTU, 231 5: MessageNexthop | MessageDistance | MessageMetric | MessageMTU, 232 6: MessageNexthop | MessageDistance | MessageMetric | MessageMTU, 233 } 234 messageWithoutNexthop := map[uint8]MessageFlag{ 235 2: zapi4MessageDistance | zapi4MessageMetric, 236 3: zapi4MessageDistance | zapi4MessageMetric, 237 4: zapi4MessageDistance | zapi4MessageMetric, 238 5: MessageDistance | MessageMetric, 239 6: MessageDistance | MessageMetric, 240 } 241 for v := MinZapiVer; v <= MaxZapiVer; v++ { 242 //decodeFromBytes IPV4_ROUTE 243 buf := make([]byte, size[v]) 244 buf[0] = byte(routeType) 245 pos := 1 246 software := NewSoftware(v, "") 247 switch v { 248 case 2, 3: 249 buf[pos] = byte(FlagSelected.ToEach(v, software)) 250 pos++ 251 case 4, 5, 6: 252 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 253 pos += 2 254 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 255 pos += 4 256 } 257 if v == 6 { 258 binary.BigEndian.PutUint32(buf[pos:], uint32(message[v])) // frr7.5: 32bit 259 pos += 4 260 } else { 261 buf[pos] = uint8(message[v]) // before frr7.4: 8bit 262 pos++ 263 } 264 if v > 4 { 265 buf[pos] = byte(SafiUnicast) //SAFI 266 pos++ 267 buf[pos] = byte(syscall.AF_INET) //Family 268 pos++ 269 } 270 buf[pos] = 24 // PrefixLen 271 pos++ 272 ip := net.ParseIP("192.168.100.0").To4() 273 copy(buf[pos:pos+3], []byte(ip)) 274 pos += 3 275 switch v { 276 case 2, 3, 4: 277 buf[pos] = byte(1) // Number of Nexthops 278 pos++ 279 case 5, 6: 280 binary.BigEndian.PutUint16(buf[pos:], 1) // Number of Nexthops 281 pos += 2 282 binary.BigEndian.PutUint32(buf[pos:], 0) // vrfid 283 pos += 4 284 buf[pos] = byte(nexthopTypeIPv4IFIndex) 285 pos++ 286 } 287 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 288 buf[pos] = 1 289 pos++ 290 } 291 nexthop := net.ParseIP("0.0.0.0").To4() 292 copy(buf[pos:pos+4], []byte(nexthop)) 293 pos += 4 294 if v < 5 { 295 buf[pos] = 1 // Number of Ifindex 296 pos++ 297 } 298 binary.BigEndian.PutUint32(buf[pos:], 1) // Ifindex 299 pos += 4 300 buf[pos] = 0 // distance 301 pos++ 302 binary.BigEndian.PutUint32(buf[pos:], 1) // metric 303 pos += 4 304 binary.BigEndian.PutUint32(buf[pos:], 1) // mtu 305 pos += 4 306 r := &IPRouteBody{API: command[v]} 307 err := r.decodeFromBytes(buf, v, software) 308 assert.Equal(nil, err) 309 assert.Equal("192.168.100.0", r.Prefix.Prefix.String()) 310 assert.Equal(uint8(0x18), r.Prefix.PrefixLen) 311 assert.Equal(message[v], r.Message) 312 assert.Equal("0.0.0.0", r.Nexthops[0].Gate.String()) 313 switch v { 314 case 2, 3, 4: 315 assert.Equal(uint32(1), r.Nexthops[1].Ifindex) 316 case 5, 6: 317 assert.Equal(uint32(1), r.Nexthops[0].Ifindex) 318 } 319 assert.Equal(uint8(0), r.Distance) 320 assert.Equal(uint32(1), r.Metric) 321 assert.Equal(uint32(1), r.Mtu) 322 323 //serialize 324 buf, err = r.serialize(v, software) 325 assert.Equal(nil, err) 326 switch v { 327 case 2, 3: 328 assert.Equal([]byte{0x2, 0x10, byte(message[v])}, buf[0:3]) 329 pos = 3 330 case 4, 5: 331 tmpFlag := byte(0xff & FlagSelected.ToEach(v, software)) 332 assert.Equal([]byte{0x2, 0x00, 0x00, 0x00, 0x00, 0x00, tmpFlag, byte(message[v])}, buf[0:8]) 333 pos = 8 334 case 6: // frr 7.5: MessageFlag: 32bit 335 tmpFlag := byte(0xff & FlagSelected.ToEach(v, software)) 336 assert.Equal([]byte{0x2, 0x00, 0x00, 0x00, 0x00, 0x00, tmpFlag, 0x00, 0x00, 0x00, byte(message[v])}, buf[0:11]) 337 pos = 11 338 } 339 switch v { 340 case 2, 3, 4: 341 assert.Equal([]byte{0x0, 0x1}, buf[pos:pos+2]) // SAFI 342 pos += 2 343 case 5, 6: 344 assert.Equal(byte(0x1), buf[pos]) // SAFI 345 pos++ 346 assert.Equal(byte(0x2), buf[pos]) // Family 347 pos++ 348 349 } 350 351 assert.Equal(byte(24), buf[pos]) 352 pos++ 353 ip = net.ParseIP("192.168.100.0").To4() 354 assert.Equal([]byte(ip)[0:3], buf[pos:pos+3]) 355 pos += 3 356 switch v { 357 case 2, 3, 4: 358 assert.Equal(byte(2), buf[pos]) // number of nexthop 359 pos++ 360 case 5, 6: 361 assert.Equal([]byte{0x0, 0x1}, buf[pos:pos+2]) // number of nexthop 362 pos += 2 363 assert.Equal([]byte{0x0, 0x0, 0x0, 0x0}, buf[pos:pos+4]) // vrfid 364 pos += 4 365 } 366 switch v { 367 case 2, 3: 368 assert.Equal(byte(backwardNexthopTypeIPv4), buf[pos]) 369 assert.Equal(byte(nexthopTypeIFIndex), buf[pos+5]) 370 pos += 10 371 case 4: 372 assert.Equal(byte(nexthopTypeIPv4), buf[pos]) 373 assert.Equal(byte(nexthopTypeIFIndex), buf[pos+5]) 374 pos += 10 375 case 5, 6: 376 assert.Equal(byte(nexthopTypeIPv4IFIndex), buf[pos]) 377 pos += 9 378 } 379 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 380 assert.Equal(byte(0x1), buf[pos]) 381 pos++ 382 } 383 assert.Equal(byte(0x0), buf[pos]) // distance 384 bi := make([]byte, 4) 385 binary.BigEndian.PutUint32(bi, 1) 386 assert.Equal(bi, buf[pos+1:pos+5]) //metric 387 assert.Equal(bi, buf[pos+5:pos+9]) //mtu 388 389 // length invalid 390 buf = make([]byte, size[v]-8) 391 buf[0] = byte(routeConnect) 392 pos = 1 393 switch v { 394 case 2, 3: 395 buf[pos] = byte(FlagSelected.ToEach(v, software)) 396 pos++ 397 case 4, 5, 6: 398 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 399 pos += 2 400 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 401 pos += 4 402 } 403 if v == 6 { 404 binary.BigEndian.PutUint32(buf[pos:], uint32(message[v])) // frr7.5: 32bit 405 pos += 4 406 } else { 407 buf[pos] = uint8(message[v]) // before frr7.4: 8bit 408 pos++ 409 } 410 411 if v > 4 { 412 buf[pos] = byte(SafiUnicast) //SAFI 413 pos++ 414 buf[pos] = byte(syscall.AF_INET) //Family 415 pos++ 416 } 417 buf[pos] = 24 // PrefixLen 418 pos++ 419 ip = net.ParseIP("192.168.100.0").To4() 420 copy(buf[pos:pos+3], []byte(ip)) 421 pos += 3 422 switch v { 423 case 2, 3, 4: 424 buf[pos] = byte(1) // Number of Nexthops 425 pos++ 426 case 5, 6: 427 binary.BigEndian.PutUint16(buf[pos:], 1) // Number of Nexthops 428 pos += 2 429 binary.BigEndian.PutUint32(buf[pos:], 0) // vrfid 430 pos += 4 431 buf[pos] = byte(nexthopTypeIPv4IFIndex) 432 pos++ 433 } 434 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 435 buf[pos] = 1 436 pos++ 437 } 438 nexthop = net.ParseIP("0.0.0.0").To4() 439 copy(buf[pos:pos+4], []byte(nexthop)) 440 pos += 4 441 if v < 5 { 442 buf[pos] = 1 // Number of Ifindex 443 pos++ 444 } 445 binary.BigEndian.PutUint32(buf[pos:], 1) // Ifindex 446 pos += 4 447 448 r = &IPRouteBody{API: command[v]} 449 err = r.decodeFromBytes(buf, v, software) 450 switch v { 451 case 2, 3, 4: 452 assert.Equal("MessageMetric message length invalid pos:14 rest:14", err.Error()) 453 case 5: 454 assert.Equal("MessageMetric message length invalid pos:19 rest:19", err.Error()) 455 case 6: 456 assert.Equal("MessageMetric message length invalid pos:20 rest:20", err.Error()) 457 } 458 459 // no nexthop 460 switch v { 461 case 2, 3, 4: 462 buf = make([]byte, size[v]-14) 463 case 5: 464 buf = make([]byte, size[v]-19) 465 case 6: 466 buf = make([]byte, size[v]-20) 467 } 468 buf[0] = byte(routeType) 469 pos = 1 470 switch v { 471 case 2, 3: 472 buf[pos] = byte(FlagSelected.ToEach(v, software)) 473 pos++ 474 case 4, 5, 6: 475 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 476 pos += 2 477 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 478 pos += 4 479 } 480 481 if v == 6 { 482 binary.BigEndian.PutUint32(buf[pos:], uint32(messageWithoutNexthop[v])) // frr7.5: 32bit 483 pos += 4 484 } else { 485 buf[pos] = byte(messageWithoutNexthop[v]) // before frr7.4: 8bit 486 pos++ 487 } 488 489 if v > 4 { 490 buf[pos] = byte(SafiUnicast) //SAFI 491 pos++ 492 buf[pos] = byte(syscall.AF_INET) //Family 493 pos++ 494 } 495 buf[pos] = 24 // PrefixLen 496 pos++ 497 ip = net.ParseIP("192.168.100.0").To4() 498 copy(buf[pos:pos+3], []byte(ip)) 499 pos += 3 500 buf[pos] = 1 // distance 501 pos++ 502 binary.BigEndian.PutUint32(buf[pos:], 0) //metric 503 pos += 4 504 r = &IPRouteBody{API: command[v]} 505 err = r.decodeFromBytes(buf, v, software) 506 assert.Equal(nil, err) 507 } 508 } 509 510 func Test_IPRouteBody_IPv6(t *testing.T) { 511 assert := assert.New(t) 512 size := map[uint8]uint8{2: 43, 3: 43, 4: 48, 5: 55, 6: 59} 513 command := map[uint8]APIType{ 514 2: zapi3IPv6RouteAdd, 515 3: zapi3IPv6RouteAdd, 516 4: zapi4IPv6RouteAdd, 517 5: zapi6Frr7RouteAdd, 518 6: zapi6Frr7RouteAdd, 519 } 520 routeType := routeConnect 521 message := map[uint8]MessageFlag{ 522 2: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi3MessageMTU, 523 3: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi3MessageMTU, 524 4: MessageNexthop | messageIFIndex | zapi4MessageDistance | zapi4MessageMetric | zapi4MessageMTU, 525 5: MessageNexthop | MessageDistance | MessageMetric | MessageMTU, 526 6: MessageNexthop | MessageDistance | MessageMetric | MessageMTU, 527 } 528 nexthopType := map[uint8]nexthopType{ 529 2: backwardNexthopTypeIPv6, 530 3: backwardNexthopTypeIPv6, 531 4: nexthopTypeIPv6, 532 5: nexthopTypeIPv6IFIndex, 533 6: nexthopTypeIPv6IFIndex, 534 } 535 messageWithoutNexthop := map[uint8]MessageFlag{ 536 2: zapi4MessageDistance | zapi4MessageMetric, 537 3: zapi4MessageDistance | zapi4MessageMetric, 538 4: zapi4MessageDistance | zapi4MessageMetric, 539 5: MessageDistance | MessageMetric, 540 6: MessageDistance | MessageMetric, 541 } 542 for v := MinZapiVer; v <= MaxZapiVer; v++ { 543 //decodeFromBytes IPV6_ROUTE 544 buf := make([]byte, size[v]) 545 buf[0] = byte(routeType) 546 pos := 1 547 software := NewSoftware(v, "") 548 switch v { 549 case 2, 3: 550 buf[pos] = byte(FlagSelected.ToEach(v, software)) 551 pos++ 552 case 4, 5, 6: 553 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 554 pos += 2 555 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 556 pos += 4 557 } 558 559 if v == 6 { 560 binary.BigEndian.PutUint32(buf[pos:], uint32(message[v])) // frr7.5: 32bit 561 pos += 4 562 } else { 563 buf[pos] = uint8(message[v]) // before frr7.4: 8bit 564 pos++ 565 } 566 567 if v > 4 { 568 buf[pos] = byte(SafiUnicast) //SAFI 569 pos++ 570 buf[pos] = byte(syscall.AF_INET6) //Family 571 pos++ 572 } 573 buf[pos] = 64 // prefixLen 574 pos++ 575 ip := net.ParseIP("2001:db8:0:f101::").To16() 576 copy(buf[pos:pos+8], []byte(ip)) 577 pos += 8 578 switch v { 579 case 2, 3, 4: 580 buf[pos] = byte(1) // Number of Nexthops 581 pos++ 582 case 5, 6: 583 binary.BigEndian.PutUint16(buf[pos:], 1) // Number of Nexthops 584 pos += 2 585 binary.BigEndian.PutUint32(buf[pos:], 0) // vrfid 586 pos += 4 587 buf[pos] = byte(nexthopTypeIPv6IFIndex) 588 pos++ 589 } 590 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 591 buf[pos] = 1 592 pos++ 593 } 594 nexthop := net.ParseIP("::").To16() 595 copy(buf[pos:pos+16], []byte(nexthop)) 596 pos += 16 597 if v < 5 { 598 buf[pos] = 1 // Number of Ifindex 599 pos++ 600 } 601 binary.BigEndian.PutUint32(buf[pos:], 1) // Ifindex 602 pos += 4 603 buf[pos] = 0 // distance 604 pos++ 605 binary.BigEndian.PutUint32(buf[pos:], 1) // metric 606 pos += 4 607 binary.BigEndian.PutUint32(buf[pos:], 1) // mtu 608 pos += 4 609 r := &IPRouteBody{API: command[v]} 610 err := r.decodeFromBytes(buf, v, software) 611 assert.Equal(nil, err) 612 assert.Equal("2001:db8:0:f101::", r.Prefix.Prefix.String()) 613 assert.Equal(uint8(64), r.Prefix.PrefixLen) 614 assert.Equal(message[v], r.Message) 615 assert.Equal("::", r.Nexthops[0].Gate.String()) 616 switch v { 617 case 2, 3, 4: 618 assert.Equal(uint32(1), r.Nexthops[1].Ifindex) 619 case 5, 6: 620 assert.Equal(uint32(1), r.Nexthops[0].Ifindex) 621 } 622 assert.Equal(uint8(0), r.Distance) 623 assert.Equal(uint32(1), r.Metric) 624 assert.Equal(uint32(1), r.Mtu) 625 626 //serialize 627 buf, err = r.serialize(v, software) 628 assert.Equal(nil, err) 629 switch v { 630 case 2, 3: 631 assert.Equal([]byte{0x2, 0x10, byte(message[v])}, buf[0:3]) 632 pos = 3 633 case 4, 5: 634 tmpFlag := byte(0xff & FlagSelected.ToEach(v, software)) 635 assert.Equal([]byte{0x2, 0x00, 0x00, 0x00, 0x00, 0x00, tmpFlag, byte(message[v])}, buf[0:8]) 636 pos = 8 637 case 6: // frr 7.5: MessageFlag: 32bit 638 tmpFlag := byte(0xff & FlagSelected.ToEach(v, software)) 639 assert.Equal([]byte{0x2, 0x00, 0x00, 0x00, 0x00, 0x00, tmpFlag, 0x00, 0x00, 0x00, byte(message[v])}, buf[0:11]) 640 pos = 11 641 } 642 switch v { 643 case 2, 3, 4: 644 assert.Equal([]byte{0x0, 0x1}, buf[pos:pos+2]) // SAFI 645 pos += 2 646 case 5, 6: 647 assert.Equal(byte(0x1), buf[pos]) // SAFI 648 pos++ 649 assert.Equal(byte(syscall.AF_INET6), buf[pos]) // Family 650 pos++ 651 } 652 assert.Equal(byte(64), buf[pos]) 653 pos++ 654 ip = net.ParseIP("2001:db8:0:f101::").To16() 655 assert.Equal([]byte(ip)[0:8], buf[pos:pos+8]) 656 pos += 8 657 switch v { 658 case 2, 3, 4: 659 assert.Equal(byte(2), buf[pos]) // number of nexthop 660 pos++ 661 case 5, 6: 662 assert.Equal([]byte{0x0, 0x1}, buf[pos:pos+2]) // number of nexthop 663 pos += 2 664 assert.Equal([]byte{0x0, 0x0, 0x0, 0x0}, buf[pos:pos+4]) // vrfid 665 pos += 4 666 } 667 assert.Equal(byte(nexthopType[v]), buf[pos]) 668 pos++ 669 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 670 assert.Equal(byte(0x1), buf[pos]) 671 pos++ 672 } 673 ip = net.ParseIP("::").To16() 674 assert.Equal([]byte(ip), buf[pos:pos+16]) 675 pos += 16 676 switch v { // Only Quagga (ZAPI version 2,3) and FRR 3.x (ZAPI version 4) 677 case 2, 3: 678 assert.Equal(byte(nexthopTypeIFIndex), buf[pos]) 679 pos++ 680 case 4: 681 assert.Equal(byte(nexthopTypeIFIndex), buf[pos]) 682 pos++ 683 } 684 bi := make([]byte, 4) 685 binary.BigEndian.PutUint32(bi, 1) 686 assert.Equal(bi, buf[pos:pos+4]) // Ifindex 687 pos += 4 688 assert.Equal(byte(0x0), buf[pos]) // distance 689 assert.Equal(bi, buf[pos+1:pos+5]) //metric 690 assert.Equal(bi, buf[pos+5:pos+9]) //mtu 691 692 // length invalid 693 buf = make([]byte, size[v]+7) 694 buf[0] = byte(routeType) 695 pos = 1 696 switch v { 697 case 2, 3: 698 buf[pos] = byte(FlagSelected.ToEach(v, software)) 699 pos++ 700 case 4, 5, 6: 701 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 702 pos += 2 703 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 704 pos += 4 705 } 706 707 if v == 6 { 708 binary.BigEndian.PutUint32(buf[pos:], uint32(message[v])) // frr7.5: 32bit 709 pos += 4 710 } else { 711 buf[pos] = uint8(message[v]) // before frr7.4: 8bit 712 pos++ 713 } 714 715 if v > 4 { 716 buf[pos] = byte(SafiUnicast) //SAFI 717 pos++ 718 buf[pos] = byte(syscall.AF_INET6) //Family 719 pos++ 720 } 721 buf[pos] = 64 // prefixLen 722 pos++ 723 ip = net.ParseIP("2001:db8:0:f101::").To16() 724 copy(buf[pos:pos+8], []byte(ip)) 725 pos += 8 726 switch v { 727 case 2, 3, 4: 728 buf[pos] = byte(1) // Number of Nexthops 729 pos++ 730 case 5, 6: 731 binary.BigEndian.PutUint16(buf[pos:], 1) // Number of Nexthops 732 pos += 2 733 binary.BigEndian.PutUint32(buf[pos:], 0) // vrfid 734 pos += 4 735 buf[pos] = byte(nexthopTypeIPv6IFIndex) 736 pos++ 737 } 738 if v == 6 { //onlink (frr7,1, 7.2, 7.3, 7.4) 739 buf[pos] = 1 740 pos++ 741 } 742 nexthop = net.ParseIP("::").To16() 743 copy(buf[pos:pos+16], []byte(nexthop)) 744 pos += 16 745 if v < 5 { 746 buf[pos] = 1 // Number of Ifindex 747 pos++ 748 } 749 binary.BigEndian.PutUint32(buf[pos:], 1) // Ifindex 750 pos += 4 751 752 r = &IPRouteBody{API: command[v]} 753 err = r.decodeFromBytes(buf, v, software) 754 switch v { 755 case 2, 3: 756 assert.Equal("message length invalid (last) pos:39 rest:46, message:0x1f", err.Error()) 757 case 4: 758 assert.Equal("message length invalid (last) pos:39 rest:46, message:0x2f", err.Error()) 759 case 5: 760 assert.Equal("message length invalid (last) pos:44 rest:51, message:0x17", err.Error()) 761 case 6: 762 assert.Equal("message length invalid (last) pos:45 rest:52, message:0x17", err.Error()) 763 } 764 765 // no nexthop 766 switch v { 767 case 2, 3, 4: 768 buf = make([]byte, size[v]-32) 769 case 5: 770 buf = make([]byte, size[v]-37) 771 case 6: 772 buf = make([]byte, size[v]-38) 773 } 774 buf[0] = byte(routeType) 775 pos = 1 776 switch v { 777 case 2, 3: 778 buf[pos] = byte(FlagSelected.ToEach(v, software)) 779 pos++ 780 case 4, 5, 6: 781 binary.BigEndian.PutUint16(buf[pos:], 0) //Instance 782 pos += 2 783 binary.BigEndian.PutUint32(buf[pos:], uint32(FlagSelected.ToEach(v, software))) 784 pos += 4 785 } 786 787 if v == 6 { 788 binary.BigEndian.PutUint32(buf[pos:], uint32(messageWithoutNexthop[v])) // frr7.5: 32bit 789 pos += 4 790 } else { 791 buf[pos] = byte(messageWithoutNexthop[v]) // before frr7.4: 8bit 792 pos++ 793 } 794 795 if v > 4 { 796 buf[pos] = byte(SafiUnicast) //SAFI 797 pos++ 798 buf[pos] = byte(syscall.AF_INET) //Family 799 pos++ 800 } 801 buf[pos] = 16 // PrefixLen 802 pos++ 803 ip = net.ParseIP("2501::").To16() 804 copy(buf[pos:pos+2], []byte(ip)) 805 pos += 2 806 buf[pos] = 1 //distance 807 binary.BigEndian.PutUint32(buf[pos:], 0) //metic 808 r = &IPRouteBody{API: command[v]} 809 err = r.decodeFromBytes(buf, v, software) 810 assert.Equal(nil, err) 811 } 812 } 813 814 // NexthopLookup exists in only quagga (zebra API version 2 and 3) 815 func Test_nexthopLookupBody(t *testing.T) { 816 assert := assert.New(t) 817 818 //ipv4 819 //decodeFromBytes 820 pos := 0 821 buf := make([]byte, 18) 822 ip := net.ParseIP("192.168.50.0").To4() 823 copy(buf[0:4], []byte(ip)) // addr 824 pos += 4 825 binary.BigEndian.PutUint32(buf[pos:], 10) // metric 826 pos += 4 827 buf[pos] = byte(1) // numNexthop 828 pos++ 829 buf[pos] = byte(4) 830 pos++ 831 ip = net.ParseIP("172.16.1.101").To4() 832 copy(buf[pos:pos+4], []byte(ip)) 833 pos += 4 834 binary.BigEndian.PutUint32(buf[pos:], 3) 835 836 //b := &nexthopLookupBody{api: zapi3IPv4NexthopLookup} 837 b := &lookupBody{api: zapi3IPv4NexthopLookup} 838 v := uint8(2) 839 software := NewSoftware(v, "") 840 err := b.decodeFromBytes(buf, v, software) 841 assert.Equal(nil, err) 842 assert.Equal("192.168.50.0", b.addr.String()) 843 assert.Equal(uint32(10), b.metric) 844 assert.Equal(uint32(3), b.nexthops[0].Ifindex) 845 assert.Equal(nexthopType(4), b.nexthops[0].Type) 846 assert.Equal("172.16.1.101", b.nexthops[0].Gate.String()) 847 848 //serialize 849 buf, err = b.serialize(v, software) 850 ip = net.ParseIP("192.168.50.0").To4() 851 assert.Equal(nil, err) 852 assert.Equal([]byte(ip)[0:4], buf[0:4]) 853 854 // length invalid 855 buf = make([]byte, 3) 856 //b = &nexthopLookupBody{api: zapi3IPv4NexthopLookup} 857 b = &lookupBody{api: zapi3IPv4NexthopLookup} 858 err = b.decodeFromBytes(buf, v, software) 859 assert.NotEqual(nil, err) 860 861 //ipv6 862 //decodeFromBytes 863 pos = 0 864 buf = make([]byte, 46) 865 ip = net.ParseIP("2001:db8:0:f101::").To16() 866 copy(buf[0:16], []byte(ip)) 867 pos += 16 868 binary.BigEndian.PutUint32(buf[pos:], 10) 869 pos += 4 870 buf[pos] = byte(1) 871 pos++ 872 buf[pos] = byte(7) 873 pos++ 874 ip = net.ParseIP("2001:db8:0:1111::1").To16() 875 copy(buf[pos:pos+16], []byte(ip)) 876 pos += 16 877 binary.BigEndian.PutUint32(buf[pos:], 3) 878 879 b = &lookupBody{api: zapi3IPv6NexthopLookup} 880 err = b.decodeFromBytes(buf, v, software) 881 assert.Equal(nil, err) 882 assert.Equal("2001:db8:0:f101::", b.addr.String()) 883 assert.Equal(uint32(10), b.metric) 884 assert.Equal(uint32(3), b.nexthops[0].Ifindex) 885 assert.Equal(nexthopType(7), b.nexthops[0].Type) 886 assert.Equal("2001:db8:0:1111::1", b.nexthops[0].Gate.String()) 887 888 //serialize 889 buf, err = b.serialize(v, software) 890 ip = net.ParseIP("2001:db8:0:f101::").To16() 891 assert.Equal(nil, err) 892 assert.Equal([]byte(ip)[0:16], buf[0:16]) 893 894 // length invalid 895 buf = make([]byte, 15) 896 b = &lookupBody{api: zapi3IPv6NexthopLookup} 897 err = b.decodeFromBytes(buf, v, software) 898 assert.NotEqual(nil, err) 899 } 900 901 // ImportLookup exists in only quagga (zebra API version 2 and 3) 902 func Test_importLookupBody(t *testing.T) { 903 assert := assert.New(t) 904 905 //decodeFromBytes 906 pos := 0 907 buf := make([]byte, 18) 908 ip := net.ParseIP("192.168.50.0").To4() 909 copy(buf[0:4], []byte(ip)) 910 pos += 4 911 binary.BigEndian.PutUint32(buf[pos:], 10) 912 pos += 4 913 buf[pos] = byte(1) 914 pos++ 915 buf[pos] = byte(4) 916 pos++ 917 ip = net.ParseIP("172.16.1.101").To4() 918 copy(buf[pos:pos+4], []byte(ip)) 919 pos += 4 920 binary.BigEndian.PutUint32(buf[pos:], 3) 921 922 b := &lookupBody{api: zapi3IPv4ImportLookup} 923 v := uint8(2) 924 software := NewSoftware(v, "") 925 err := b.decodeFromBytes(buf, v, software) 926 assert.Equal(nil, err) 927 assert.Equal("192.168.50.0", b.addr.String()) 928 assert.Equal(uint32(10), b.metric) 929 assert.Equal(uint32(3), b.nexthops[0].Ifindex) 930 assert.Equal(nexthopType(4), b.nexthops[0].Type) 931 assert.Equal("172.16.1.101", b.nexthops[0].Gate.String()) 932 933 //serialize 934 b.prefixLength = uint8(24) 935 buf, err = b.serialize(v, software) 936 ip = net.ParseIP("192.168.50.0").To4() 937 assert.Equal(nil, err) 938 assert.Equal(uint8(24), buf[0]) 939 assert.Equal([]byte(ip)[0:4], buf[1:5]) 940 941 // length invalid 942 buf = make([]byte, 3) 943 b = &lookupBody{api: zapi3IPv4ImportLookup} 944 err = b.decodeFromBytes(buf, v, software) 945 assert.NotEqual(nil, err) 946 } 947 948 func Test_NexthopRegisterBody(t *testing.T) { 949 assert := assert.New(t) 950 951 // Input binary 952 bufIn := []byte{ 953 0x01, uint8(syscall.AF_INET >> 8), uint8(syscall.AF_INET & 0xff), 0x20, // connected(1 byte)=1, afi(2 bytes)=AF_INET, prefix_len(1 byte)=32 954 0xc0, 0xa8, 0x01, 0x01, // prefix(4 bytes)="192.168.1.1" 955 0x00, uint8(syscall.AF_INET6 >> 8), uint8(syscall.AF_INET6 & 0xff), 0x80, // connected(1 byte)=0, afi(2 bytes)=AF_INET6, prefix_len(1 byte)=128 956 0x20, 0x01, 0x0d, 0xb8, // prefix(16 bytes)="2001:db8:1:1::1" 957 0x00, 0x01, 0x00, 0x01, 958 0x00, 0x00, 0x00, 0x00, 959 0x00, 0x00, 0x00, 0x01, 960 } 961 command := map[uint8]APIType{ 962 2: zapi3NexthopRegister, 963 3: zapi3NexthopRegister, 964 4: zapi4NexthopRegister, 965 5: zapi5Frr5NexthopRegister, 966 6: nexthopRegister, 967 } 968 for v := MinZapiVer; v <= MaxZapiVer; v++ { 969 // Test decodeFromBytes() 970 software := NewSoftware(v, "") 971 b := &NexthopRegisterBody{api: command[v].ToCommon(v, software)} 972 err := b.decodeFromBytes(bufIn, v, software) 973 assert.Nil(err) 974 975 // Test decoded values 976 assert.Equal(uint8(1), b.Nexthops[0].connected) 977 assert.Equal(uint16(syscall.AF_INET), b.Nexthops[0].Family) 978 assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Nexthops[0].Prefix) 979 assert.Equal(uint8(0), b.Nexthops[1].connected) 980 assert.Equal(uint16(syscall.AF_INET6), b.Nexthops[1].Family) 981 assert.Equal(net.ParseIP("2001:db8:1:1::1").To16(), b.Nexthops[1].Prefix) 982 983 // Test serialize() 984 bufOut, err := b.serialize(v, software) 985 assert.Nil(err) 986 987 // Test serialised value 988 assert.Equal(bufIn, bufOut) 989 } 990 } 991 992 func Test_NexthopUpdateBody(t *testing.T) { 993 assert := assert.New(t) 994 995 size := map[uint8]uint8{2: 21, 3: 21, 4: 22, 5: 26, 6: 34} 996 command := map[uint8]APIType{ 997 2: zapi3NexthopUpdate, 998 3: zapi3NexthopUpdate, 999 4: zapi4NexthopUpdate, 1000 5: zapi5Frr5NexthopUpdate, 1001 6: nexthopUpdate, 1002 } 1003 nexthopType := map[uint8]nexthopType{ 1004 2: backwardNexthopTypeIPv4IFIndex, 1005 3: backwardNexthopTypeIPv4IFIndex, 1006 4: nexthopTypeIPv4IFIndex, 1007 5: nexthopTypeIPv4IFIndex, 1008 6: nexthopTypeIPv4IFIndex, 1009 } 1010 1011 for v := MinZapiVer; v <= MaxZapiVer; v++ { 1012 // Input binary 1013 bufIn := make([]byte, size[v]) 1014 pos := 0 1015 if v == 6 { // frr7.5 1016 // message flag 1017 copy(bufIn[pos:pos+4], []byte{0x00, 0x00, 0x00, 0x00}) 1018 pos += 4 1019 } 1020 // afi(2 bytes)=AF_INET, prefix_len(1 byte)=32, prefix(4 bytes)="192.168.1.1" 1021 copy(bufIn[pos:pos+7], []byte{0x00, 0x02, 0x20, 0xc0, 0xa8, 0x01, 0x01}) 1022 pos += 7 1023 1024 if v > 4 { // Type(1byte), Instance(2byte) 1025 copy(bufIn[pos:pos+3], []byte{byte(routeConnect), 0x00, 0x00}) 1026 pos += 3 1027 } 1028 if v > 3 { // Distance 1029 bufIn[pos] = 0 1030 pos++ 1031 } 1032 // metric(4 bytes)=1, number of nexthops(1 byte)=1 1033 copy(bufIn[pos:pos+5], []byte{0x00, 0x00, 0x00, 0x01, 0x01}) 1034 pos += 5 1035 if v == 6 { // version == 6 and not frr6 1036 binary.BigEndian.PutUint32(bufIn[pos:], 0) //vrfid 1037 pos += 4 1038 } 1039 bufIn[pos] = byte(nexthopType[v]) 1040 pos++ 1041 if v == 6 { // frr7.3 and later 1042 bufIn[pos] = byte(0) // nexthop flag 1043 pos++ 1044 } 1045 // nexthop_ip(4 bytes)="192.168.0.1", nexthop_Ifindex(4 byte)=2 1046 copy(bufIn[pos:pos+8], []byte{0xc0, 0xa8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02}) 1047 pos += 8 1048 if v == 5 { // frr7.3&7.4 (latest software of zapi v6) depends on nexthop flag 1049 bufIn[pos] = byte(0) // label num 1050 pos++ 1051 } 1052 1053 // Test decodeFromBytes() 1054 software := NewSoftware(v, "") 1055 b := &NexthopUpdateBody{API: command[v].ToCommon(v, software)} 1056 err := b.decodeFromBytes(bufIn, v, software) 1057 assert.Nil(err) 1058 1059 // Test decoded values 1060 assert.Equal(uint8(syscall.AF_INET), b.Prefix.Family) 1061 assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Prefix.Prefix) 1062 assert.Equal(uint32(1), b.Metric) 1063 nexthop := Nexthop{ 1064 Type: nexthopType[v], 1065 Gate: net.ParseIP("192.168.1.1").To4(), 1066 Ifindex: uint32(2), 1067 } 1068 assert.Equal(1, len(b.Nexthops)) 1069 assert.Equal(nexthop, b.Nexthops[0]) 1070 } 1071 } 1072 1073 func Test_GetLabelChunkBody(t *testing.T) { 1074 assert := assert.New(t) 1075 1076 // Test only with ZAPI version 5 and 6 1077 routeType := RouteBGP 1078 for v := uint8(5); v <= MaxZapiVer; v++ { 1079 //decodeFromBytes 1080 buf := make([]byte, 12) 1081 buf[0] = byte(routeType) // Route Type 1082 binary.BigEndian.PutUint16(buf[1:], 0) //Instance 1083 buf[3] = 0 //Keep 1084 binary.BigEndian.PutUint32(buf[4:], 80) //Start 1085 binary.BigEndian.PutUint32(buf[8:], 89) //End 1086 1087 b := &GetLabelChunkBody{} 1088 software := NewSoftware(v, "") 1089 err := b.decodeFromBytes(buf, v, software) 1090 assert.Equal(nil, err) 1091 1092 //serialize 1093 b.ChunkSize = 10 1094 buf, err = b.serialize(v, software) 1095 assert.Equal(nil, err) 1096 assert.Equal(byte(routeType), buf[0]) 1097 bi := make([]byte, 4) 1098 binary.BigEndian.PutUint32(bi, 10) 1099 assert.Equal(bi, buf[4:8]) // Chunksize 1100 } 1101 } 1102 1103 func Test_vrfLabelBody(t *testing.T) { 1104 assert := assert.New(t) 1105 // Test only with ZAPI version 5 and 6 1106 for v := uint8(5); v <= MaxZapiVer; v++ { 1107 //decodeFromBytes 1108 bufIn := make([]byte, 6) 1109 binary.BigEndian.PutUint32(bufIn[0:], 80) //label 1110 bufIn[4] = byte(afiIP) 1111 bufIn[5] = byte(lspBGP) 1112 b := &vrfLabelBody{} 1113 software := NewSoftware(v, "") 1114 err := b.decodeFromBytes(bufIn, v, software) 1115 assert.Equal(nil, err) 1116 //serialize 1117 var bufOut []byte 1118 bufOut, err = b.serialize(v, software) 1119 assert.Equal(nil, err) 1120 assert.Equal(bufIn, bufOut) 1121 } 1122 } 1123 1124 func FuzzZapi(f *testing.F) { 1125 1126 f.Fuzz(func(t *testing.T, data []byte) { 1127 1128 if len(data) < 16 { 1129 return 1130 } 1131 1132 for v := MinZapiVer; v <= MaxZapiVer; v++ { 1133 1134 ZAPIHeaderSize := int(HeaderSize(v)) 1135 1136 hd := &Header{} 1137 err := hd.decodeFromBytes(data[:ZAPIHeaderSize]) 1138 1139 if err != nil { 1140 return 1141 } 1142 1143 software := NewSoftware(v, "") 1144 parseMessage(hd, data[:ZAPIHeaderSize], software) 1145 } 1146 }) 1147 }