Revision 7ba182b5

b/kvm-vif-bridge
87 87
  #needed in bridged mode where the packets seems to arrive from the
88 88
  #bridge and not from the tap
89 89
	cat >$FILE <<EOF
90
IFACE=$1
90
INDEV=$1
91 91
IP=$IP
92 92
MAC=$MAC
93 93
HOSTNAME=$INSTANCE
b/nfdhcpd/nfdhcpd
126 126
        logging.warn("Unable to open binding file %s: %s", path, str(e))
127 127
        return None
128 128

  
129
    ifname = os.path.basename(path)
129
    tap = os.path.basename(path)
130
    indev = None
130 131
    mac = None
131 132
    ips = None
132
    link = None
133 133
    hostname = None
134 134
    subnet = None
135 135
    gateway = None
......
144 144
            mac = line.strip().split("=")[1]
145 145
        elif line.startswith("HOSTNAME="):
146 146
            hostname = line.strip().split("=")[1]
147
        elif line.startswith("IFACE="):
148
            iface = line.strip().split("=")[1]
147
        elif line.startswith("INDEV="):
148
            indev = line.strip().split("=")[1]
149 149
        elif line.startswith("SUBNET="):
150 150
            subnet = line.strip().split("=")[1]
151 151
        elif line.startswith("GATEWAY="):
......
155 155
        elif line.startswith("GATEWAY6="):
156 156
            gateway6 = line.strip().split("=")[1]
157 157

  
158
    return Client(ifname=ifname, mac=mac, ips=ips, link=link,
159
                  hostname=hostname, iface=iface, subnet=subnet,
158
    return Client(tap=tap, mac=mac, ips=ips, 
159
                  hostname=hostname, indev=indev, subnet=subnet,
160 160
                  gateway=gateway, subnet6=subnet6, gateway6=gateway6 )
161 161

  
162 162
class ClientFileHandler(pyinotify.ProcessEvent):
......
170 170
        Currently this removes an interface from the watch list
171 171

  
172 172
        """
173
        self.server.remove_iface(event.name)
173
        self.server.remove_tap(event.name)
174 174

  
175 175
    def process_IN_CLOSE_WRITE(self, event): # pylint: disable=C0103
176 176
        """ Add file handler
......
178 178
        Currently this adds an interface to the watch list
179 179

  
180 180
        """
181
        self.server.add_iface(os.path.join(event.path, event.name))
181
        self.server.add_tap(os.path.join(event.path, event.name))
182 182

  
183 183

  
184 184
class Client(object):
185
    def __init__(self, ifname=None, mac=None, ips=None, link=None,
186
                 hostname=None, iface=None, subnet=None, gateway=None,
187
                 subnet6=None, gateway6=None ):
185
    def __init__(self, tap=None, indev=None, mac=None, ips=None, hostname=None, 
186
                 subnet=None, gateway=None, subnet6=None, gateway6=None ):
188 187
        self.mac = mac
189 188
        self.ips = ips
190 189
        self.hostname = hostname
191
        self.link = link
192
        self.iface = iface
193
        self.ifname = ifname
190
        self.indev = indev
191
        self.tap = tap
194 192
        self.subnet = subnet
195 193
        self.gateway = gateway
196
        self.net = Subnet(net=subnet, gw=gateway, dev=ifname)
194
        self.net = Subnet(net=subnet, gw=gateway, dev=tap)
197 195
        self.subnet6 = subnet6
198 196
        self.gateway6 = gateway6
199
        self.net6 = Subnet(net=subnet6, gw=gateway6, dev=ifname)
197
        self.net6 = Subnet(net=subnet6, gw=gateway6, dev=tap)
200 198

  
201 199
    @property
202 200
    def ip(self):
......
354 352
        q.set_mode(nfqueue.NFQNL_COPY_PACKET)
355 353
        self.nfq[q.get_fd()] = q
356 354

  
357
    def sendp(self, data, iface):
355
    def sendp(self, data, dev):
358 356
        """ Send a raw packet using a layer-2 socket
359 357

  
360 358
        """
......
362 360
        if isinstance(data, BasePacket):
363 361
            data = str(data)
364 362

  
365
        self.l2socket.bind((iface, ETH_P_ALL))
363
        self.l2socket.bind((dev, ETH_P_ALL))
366 364
        count = self.l2socket.send(data)
367 365
        ldata = len(data)
368 366
        if count != ldata:
369 367
            logging.warn("Truncated send on %s (%d/%d bytes sent)",
370
                         iface, count, ldata)
368
                         dev, count, ldata)
371 369

  
372 370
    def build_config(self):
373 371
        self.clients.clear()
374 372

  
375 373
        for path in glob.glob(os.path.join(self.data_path, "*")):
376
            self.add_iface(path)
374
            self.add_tap(path)
377 375

  
378 376
    def get_ifindex(self, iface):
379 377
        """ Get the interface index from sysfs
......
389 387
            f = open(path, 'r')
390 388
        except EnvironmentError:
391 389
            logging.debug("%s is probably down, removing", iface)
392
            self.remove_iface(iface)
390
            self.remove_tap(iface)
393 391

  
394 392
            return ifindex
395 393

  
......
403 401
        except EnvironmentError, e:
404 402
            logging.warn("Error reading %s's ifindex from sysfs: %s",
405 403
                         iface, str(e))
406
            self.remove_iface(iface)
404
            self.remove_tap(iface)
407 405
        finally:
408 406
            f.close()
409 407

  
......
423 421
            f = open(path, 'r')
424 422
        except EnvironmentError:
425 423
            logging.debug("%s is probably down, removing", iface)
426
            self.remove_iface(iface)
424
            self.remove_tap(iface)
427 425
            return addr
428 426

  
429 427
        try:
......
436 434

  
437 435
        return addr
438 436

  
439
    def add_iface(self, path):
437
    def add_tap(self, path):
440 438
        """ Add an interface to monitor
441 439

  
442 440
        """
443
        iface = os.path.basename(path)
441
        tap = os.path.basename(path)
444 442

  
445
        logging.debug("Updating configuration for %s", iface)
443
        logging.debug("Updating configuration for %s", tap)
446 444
        binding = parse_binding_file(path)
447 445
        if binding is None:
448 446
            return
449
        ifindex = self.get_ifindex(binding.iface)
447
        ifindex = self.get_ifindex(binding.indev)
450 448

  
451 449
        if ifindex is None:
452
            logging.warn("Stale configuration for %s found", iface)
450
            logging.warn("Stale configuration for %s found", tap)
453 451
        else:
454 452
            if binding.is_valid():
455 453
                self.clients[binding.mac] = binding
456
                logging.debug("Added client %s on %s", binding.hostname, iface)
457
                self.ifaces[ifindex] = binding.iface
454
                logging.debug("Added client %s on %s", binding.hostname, tap)
455
                self.ifaces[ifindex] = binding.indev
458 456

  
459
    def remove_iface(self, ifname):
457
    def remove_tap(self, tap):
460 458
        """ Cleanup clients on a removed interface
461 459

  
462 460
        """
463 461
        for mac in self.clients.keys():
464
            if self.clients[mac].ifname == ifname:
465
                iface = self.clients[mac].iface
462
            logging.debug("mac %s", mac)
463
            logging.debug("tap %s", self.clients[mac].tap)
464
            logging.debug("indev %s", self.clients[mac].indev)
465
            if self.clients[mac].tap == tap:
466
                indev = self.clients[mac].indev
466 467
                del self.clients[mac]
467 468

  
468 469
        for ifindex in self.ifaces.keys():
469
            if self.ifaces[ifindex] == ifname == iface:
470
            if self.ifaces[ifindex] == indev == tap:
470 471
                del self.ifaces[ifindex]
471 472

  
472
        logging.debug("Removed interface %s", ifname)
473
        logging.debug("Removed interface %s", tap)
473 474

  
474 475
    def dhcp_response(self, i, payload): # pylint: disable=W0613,R0914
475
        """ Generate a reply to a BOOTP/DHCP request
476
        """ Generate a reply to bnetfilter-queue-deva BOOTP/DHCP request
476 477

  
477 478
        """
478
        logging.info("%s",payload)
479
        indev = payload.get_indev()
479
        indevidx = payload.get_indev()
480 480
        try:
481 481
            # Get the actual interface from the ifindex
482
            iface = self.ifaces[indev]
482
            indev = self.ifaces[indevidx]
483 483
        except KeyError:
484 484
            # We don't know anything about this interface, so accept the packet
485 485
            # and return
......
508 508
        try:
509 509
            binding = self.clients[mac]
510 510
        except KeyError:
511
            logging.warn("Invalid client %s on %s", mac, iface)
511
            logging.warn("Invalid client %s on %s", mac, indev)
512 512
            return
513 513

  
514
        if iface != binding.iface:
514
        if indev != binding.indev:
515 515
            logging.warn("Received spoofed DHCP request for %s from interface"
516
                         " %s instead of %s", mac, iface, binding.iface)
516
                         " %s instead of %s", mac, indev, binding.indev)
517 517
            return
518 518

  
519
        resp = Ether(dst=mac, src=self.get_iface_hw_addr(iface))/\
519
        resp = Ether(dst=mac, src=self.get_iface_hw_addr(indev))/\
520 520
               IP(src=DHCP_DUMMY_SERVER_IP, dst=binding.ip)/\
521 521
               UDP(sport=pkt.dport, dport=pkt.sport)/resp
522 522
        subnet = binding.net
523 523

  
524 524
        if not DHCP in pkt:
525 525
            logging.warn("Invalid request from %s on %s, no DHCP"
526
                         " payload found", binding.mac, iface)
526
                         " payload found", binding.mac, binding.tap)
527 527
            return
528 528

  
529 529
        dhcp_options = []
......
535 535
                requested_addr = opt[1]
536 536

  
537 537
        logging.info("%s from %s on %s", DHCP_TYPES.get(req_type, "UNKNOWN"),
538
                     binding.mac, iface)
538
                     binding.mac, binding.tap)
539 539

  
540 540
        if req_type == DHCPREQUEST and requested_addr != binding.ip:
541 541
            resp_type = DHCPNAK
542 542
            logging.info("Sending DHCPNAK to %s on %s: requested %s"
543
                         " instead of %s", binding.mac, iface, requested_addr,
543
                         " instead of %s", binding.mac, binding.tap, requested_addr,
544 544
                         binding.ip)
545 545

  
546 546
        elif req_type in (DHCPDISCOVER, DHCPREQUEST):
......
568 568

  
569 569
        elif req_type == DHCPRELEASE:
570 570
            # Log and ignore
571
            logging.info("DHCPRELEASE from %s on %s", binding.mac, iface)
571
            logging.info("DHCPRELEASE from %s on %s", binding.mac, binding.tap )
572 572
            return
573 573

  
574 574
        # Finally, always add the server identifier and end options
......
580 580
        resp /= DHCP(options=dhcp_options)
581 581

  
582 582
        logging.info("%s to %s (%s) on %s", DHCP_TYPES[resp_type], mac,
583
                     binding.ip, iface)
584
        self.sendp(resp, iface)
583
                     binding.ip, binding.tap)
584
        self.sendp(resp, indev )
585 585

  
586 586
    def rs_response(self, i, payload): # pylint: disable=W0613
587 587
        """ Generate a reply to a BOOTP/DHCP request
588 588

  
589 589
        """
590
        indev = payload.get_indev()
590
        indevidx = payload.get_indev()
591 591
        try:
592 592
            # Get the actual interface from the ifindex
593
            iface = self.ifaces[indev]
593
            indev = self.ifaces[indevidx]
594 594
        except KeyError:
595 595
            logging.debug("Ignoring router solicitation on"
596 596
                          " unknown interface %d", indev)
......
599 599
            payload.set_verdict(nfqueue.NF_ACCEPT)
600 600
            return
601 601

  
602
        ifmac = self.get_iface_hw_addr(iface)
603
        binding = [ b for b in self.clients.values() if b.ifname == iface ]
602
        binding = [ b for b in self.clients.values() if b.tap == indev ]
604 603
        subnet = binding[0].net6
605 604
        if subnet.net is None:
606 605
          logging.debug("No IPv6 network assigned for the interface")
......
610 609
        # Signal the kernel that it shouldn't further process the packet
611 610
        payload.set_verdict(nfqueue.NF_DROP)
612 611

  
613
        resp = Ether(src=self.get_iface_hw_addr(iface))/\
612
        resp = Ether(src=self.get_iface_hw_addr(indev))/\
614 613
               IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
615 614
               ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
616 615
                                     prefixlen=subnet.prefixlen)
......
619 618
            resp /= ICMPv6NDOptRDNSS(dns=self.ipv6_nameservers,
620 619
                                     lifetime=self.ra_period * 3)
621 620

  
622
        logging.info("RA on %s for %s", iface, subnet.net)
623
        self.sendp(resp, iface)
621
        logging.info("RA on %s for %s", indev, subnet.net)
622
        self.sendp(resp, indev)
624 623

  
625 624
    def ns_response(self, i, payload): # pylint: disable=W0613
626 625
        """ Generate a reply to an ICMPv6 neighbor solicitation
627 626

  
628 627
        """
629
        indev = payload.get_indev()
628
        indevidx = payload.get_indev()
630 629
        try:
631 630
            # Get the actual interface from the ifindex
632
            iface = self.ifaces[indev]
631
            indev = self.ifaces[indevidx]
633 632
        except KeyError:
634 633
            logging.debug("Ignoring neighbour solicitation on"
635 634
                          " unknown interface %d", indev)
......
638 637
            payload.set_verdict(nfqueue.NF_ACCEPT)
639 638
            return
640 639

  
641
        ifmac = self.get_iface_hw_addr(iface)
642
        binding = [ b for b in self.clients.values() if b.ifname == iface ]
640
        binding = [ b for b in self.clients.values() if b.tap == indev ]
643 641
        subnet = binding[0].net6
644 642
        if subnet.net is None:
645 643
          logging.debug("No IPv6 network assigned for the interface")
646 644
          return
647 645

  
648
        ifll = subnet.make_ll64(ifmac)
646
        indevmac = self.get_iface_hw_addr(indev)
647

  
648
        ifll = subnet.make_ll64(indevmac)
649 649

  
650 650
        ns = IPv6(payload.get_data())
651 651

  
......
660 660
            client_lladdr = ns.lladdr
661 661
        except AttributeError:
662 662
            return 1
663

  
664
        resp = Ether(src=ifmac, dst=client_lladdr)/\
663
        
664
        resp = Ether(src=indevmac, dst=client_lladdr)/\
665 665
               IPv6(src=str(ifll), dst=ns.src)/\
666 666
               ICMPv6ND_NA(R=1, O=0, S=1, tgt=ns.tgt)/\
667
               ICMPv6NDOptDstLLAddr(lladdr=ifmac)
667
               ICMPv6NDOptDstLLAddr(lladdr=indevmac)
668 668

  
669
        logging.info("NA on %s for %s", iface, ns.tgt)
670
        self.sendp(resp, iface)
669
        logging.info("NA on %s for %s", indev, ns.tgt)
670
        self.sendp(resp, indev)
671 671
        return 1
672 672

  
673 673
    def send_periodic_ra(self):
......
680 680
        start = time.time()
681 681
        i = 0
682 682
        for binding in self.clients.values():
683
            iface = binding.ifname
684
            ifmac = binding.mac
683
            tap = binding.tap
684
            indev = binding.indev
685
            mac = binding.mac
685 686
            subnet = binding.net6
686 687
            if subnet.net is None:
687 688
                logging.debug("Skipping periodic RA on interface %s,"
688
                              " as it is not IPv6-connected", iface)
689
                              " as it is not IPv6-connected", tap)
689 690
                continue
690

  
691
            ifll = subnet.make_ll64(ifmac)
692
            resp = Ether(src=ifmac)/\
691
            indevmac = self.get_iface_hw_addr(indev)
692
            ifll = subnet.make_ll64(indevmac)
693
            resp = Ether(src=indevmac)/\
693 694
                   IPv6(src=str(ifll))/ICMPv6ND_RA(routerlifetime=14400)/\
694 695
                   ICMPv6NDOptPrefixInfo(prefix=str(subnet.prefix),
695 696
                                         prefixlen=subnet.prefixlen)
......
697 698
                resp /= ICMPv6NDOptRDNSS(dns=self.ipv6_nameservers,
698 699
                                         lifetime=self.ra_period * 3)
699 700
            try:
700
                self.sendp(resp, iface)
701
                self.sendp(resp, indev)
701 702
            except socket.error, e:
702
                logging.warn("Periodic RA on %s failed: %s", iface, str(e))
703
                logging.warn("Periodic RA on %s failed: %s", tap, str(e))
703 704
            except Exception, e:
704 705
                logging.warn("Unkown error during periodic RA on %s: %s",
705
                             iface, str(e))
706
                             tap, str(e))
706 707
            i += 1
707 708
        logging.debug("Sent %d RAs in %.2f seconds", i, time.time() - start)
708 709

  

Also available in: Unified diff