@@ -518,29 +518,44 @@ def get_nth_ip_from_prefix(pfx: netaddr.IPNetwork, n_id: int) -> str:
518
518
check_interface_host_bits: Check whether the IP addresses on an interface have host bits. The check is disabled
519
519
for special prefixes (IPv4: /31, /32, IPv6: /127, /128)
520
520
"""
521
- def check_interface_host_bits (intf : Box , node : Box ) -> bool :
521
+ def check_interface_host_bits (intf : Box , node : Box , link : typing . Optional [ Box ] = None ) -> bool :
522
522
OK = True
523
523
524
+ if 'ifname' in intf :
525
+ intf_name = f'{ intf .ifname } ({ intf .name } )' if 'name' in intf else intf .ifname
526
+ elif link is not None :
527
+ intf_name = link ._linkname
528
+ else :
529
+ intf_name = ''
530
+
524
531
for af in log .AF_LIST :
525
532
if af not in intf : # Skip unusued AFs
526
533
continue
527
534
if not isinstance (intf [af ],str ): # Skip unnumbered interfaces
528
535
continue
529
536
pfx = netaddr .IPNetwork (intf [af ])
537
+ if pfx [0 ].is_multicast ():
538
+ log .error (
539
+ f'Interfaces cannot have multicast { af } addresses ({ intf [af ]} on { node .name } /{ intf_name } )' ,
540
+ log .IncorrectValue ,
541
+ 'links' )
542
+ OK = False
543
+ continue
544
+
530
545
if pfx .last <= pfx .first + 1 : # Are we dealing with special prefix (loopback or /31)
531
546
continue # ... then it's OK not to have host bits
532
547
533
548
if str (pfx ) == str (pfx .cidr ): # Does the IP address have host bits -- is it different from its CIDR subnet?
534
549
log .error (
535
- f'Address { intf [af ]} on interface { intf . ifname } / node { node .name } does not contain host bits' ,
550
+ f'Address { intf [af ]} on node { node .name } / { intf_name } does not contain host bits' ,
536
551
log .IncorrectValue ,
537
552
'links' )
538
553
OK = False
539
554
continue
540
555
541
556
if str (pfx [- 1 ]) == str (pfx .ip ) and af == 'ipv4' :
542
557
log .error (
543
- f'Address { intf [af ]} on interface { intf . ifname } / node { node .name } is a subnet broadcast address' ,
558
+ f'Address { intf [af ]} on node { node .name } / { intf_name } is a subnet broadcast address' ,
544
559
log .IncorrectValue ,
545
560
'links' )
546
561
OK = False
@@ -571,17 +586,7 @@ def set_interface_address(intf: Box, af: str, pfx: netaddr.IPNetwork, node_id: i
571
586
'links' )
572
587
return False
573
588
574
- if str (intf_pfx ) != str (intf_pfx .cidr ): # Does the IP address have host bits -- is it different from its CIDR subnet?
575
- return True # That's it -- the user knows what she's doing
576
-
577
- if intf_pfx .last <= intf_pfx .first + 1 : # Are we dealing with special prefix (loopback or /31)
578
- return True # ... then it's OK not to have host bits
579
-
580
- log .error (
581
- f'Address { intf [af ]} for node { intf .node } does not contain host bits' ,
582
- log .IncorrectValue ,
583
- 'links' )
584
- return False
589
+ return True # Further checks done in check_interface_host_bits
585
590
586
591
# No static interface address, or static address specified as relative node_id
587
592
try :
@@ -601,7 +606,8 @@ def set_interface_address(intf: Box, af: str, pfx: netaddr.IPNetwork, node_id: i
601
606
602
607
If the interface address is set, validate that it's a valid address (can't be int)
603
608
"""
604
- def IPAM_unnumbered (link : Box , af : str , pfx : typing .Optional [bool ], ndict : Box ) -> None :
609
+ def IPAM_unnumbered (link : Box , af : str , pfx : typing .Optional [bool ], ndict : Box ) -> bool :
610
+ OK = True
605
611
for intf in link .interfaces :
606
612
if not af in intf : # No static address
607
613
if isinstance (pfx ,bool ): # Set it to link bool value if it exists
@@ -615,29 +621,43 @@ def IPAM_unnumbered(link: Box, af: str, pfx: typing.Optional[bool], ndict: Box)
615
621
f'Node { intf .node } is using host index { intf [af ]} for { af } on an unnumbered link' ,
616
622
log .IncorrectValue ,
617
623
'links' )
624
+ OK = False
625
+
626
+ return OK
618
627
619
- def IPAM_sequential (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> None :
628
+ def IPAM_sequential (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> bool :
620
629
start = 1 if pfx .last != pfx .first + 1 else 0
621
630
gwid = get_gateway_id (link )
631
+ OK = True
622
632
for count ,intf in enumerate (link .interfaces ):
623
633
if count + start == gwid : # Would the next address overlap with gateway ID
624
634
start = start + 1 # ... no big deal, just move the starting point ;)
625
- set_interface_address (intf ,af ,pfx ,count + start )
635
+ OK = set_interface_address (intf ,af ,pfx ,count + start ) and OK
636
+
637
+ return OK
626
638
627
- def IPAM_p2p (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> None :
639
+ def IPAM_p2p (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> bool :
628
640
start = 1 if pfx .last != pfx .first + 1 else 0
641
+ OK = True
629
642
for count ,intf in enumerate (sorted (link .interfaces , key = lambda intf : intf .node )):
630
- set_interface_address (intf ,af ,pfx ,count + start )
643
+ OK = set_interface_address (intf ,af ,pfx ,count + start ) and OK
631
644
632
- def IPAM_id_based (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> None :
645
+ return OK
646
+
647
+ def IPAM_id_based (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> bool :
648
+ OK = True
633
649
for intf in link .interfaces :
634
- set_interface_address (intf ,af ,pfx ,ndict [intf .node ].id )
650
+ OK = set_interface_address (intf ,af ,pfx ,ndict [intf .node ].id ) and OK
651
+
652
+ return OK
635
653
636
- def IPAM_loopback (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> None :
654
+ def IPAM_loopback (link : Box , af : str , pfx : netaddr .IPNetwork , ndict : Box ) -> bool :
637
655
for intf in link .interfaces :
638
656
pfx .prefixlen = 128 if ':' in str (pfx ) else 32
639
657
intf [af ] = str (pfx )
640
658
659
+ return True
660
+
641
661
IPAM_dispatch : typing .Final [dict ] = {
642
662
'unnumbered' : IPAM_unnumbered ,
643
663
'p2p' : IPAM_p2p ,
@@ -669,6 +689,7 @@ def assign_interface_addresses(link: Box, addr_pools: Box, ndict: Box, defaults:
669
689
link .pop ('unnumbered' )
670
690
return
671
691
692
+ error = False
672
693
for af in ('ipv4' ,'ipv6' ):
673
694
if not af in pfx_list : # Skip address families not used on the link
674
695
continue
@@ -686,6 +707,7 @@ def assign_interface_addresses(link: Box, addr_pools: Box, ndict: Box, defaults:
686
707
strings .extra_data_printout (f'{ link } ' ),
687
708
log .IncorrectValue ,
688
709
'links' )
710
+ error = True
689
711
continue
690
712
691
713
if 'allocation' in pfx_list :
@@ -707,14 +729,25 @@ def assign_interface_addresses(link: Box, addr_pools: Box, ndict: Box, defaults:
707
729
more_hints = hints ,
708
730
category = log .IncorrectValue ,
709
731
module = 'links' )
732
+ error = True
710
733
continue
711
734
712
735
if not allocation_policy in IPAM_dispatch :
713
736
log .error (
714
737
f'Invalid IP address allocation policy specified in prefix { pfx_list } found on { link ._linkname } ' ,
715
738
log .IncorrectValue ,
716
739
'links' )
717
- IPAM_dispatch [allocation_policy ](link ,af ,pfx_net ,ndict ) # execute IPAM policy to get AF addresses on interfaces
740
+ error = True
741
+
742
+ # execute IPAM policy to get AF addresses on interfaces
743
+ if not IPAM_dispatch [allocation_policy ](link ,af ,pfx_net ,ndict ):
744
+ error = True
745
+
746
+ if error :
747
+ return
748
+
749
+ for intf in link .interfaces :
750
+ check_interface_host_bits (intf ,ndict [intf .node ],link )
718
751
719
752
"""
720
753
cleanup 'af: False' entries from interfaces
0 commit comments