Ejemplo n.º 1
0
 def deserialize(doc):
     obj = eval(doc)
     mat = MAT(obj['sid'], obj['vid'])
     mat.props['hid'] = obj['hid']
     for (hid, mac) in obj['mac'].items():
         # Note: json file can only use str as key
         # so we need to transfer hid back to int first
         mat.props['mac'][int(hid)] = MACAddress(mac)
     return mat
Ejemplo n.º 2
0
 def __init__(self, sid, vid):
     super(MAT, self).__init__(name='MAT[%d]' % vid)
     self.props['sid'] = sid
     self.props['vid'] = vid
     self.props['hid'] = {}  # [str(mac)] = hid
     self.props['mac'] = {}  # [hid] = mac
     self.props['lock'] = threading.Lock()
     self.props['mac'][0xFFFF] = MACAddress("FF:FF:FF:FF:FF:FF")
     self.props['hid']['FF:FF:FF:FF:FF:FF'] = 0xFFFF
Ejemplo n.º 3
0
 def translate(self, mac):
     if not str(mac) in self.props['hid']:
         with self.props['lock']:
             if not str(mac) in self.props['hid']:
                 hid = random.randint(1, MAT.reserved)
                 while hid in self.props['mac']:
                     hid = random.randint(1, MAT.reserved)
                 self.props['hid'][str(mac)] = hid
                 self.props['mac'][hid] = mac
     trans_mac = MACAddress()
     trans_mac.setSid(self.props['sid'])
     trans_mac.setVid(self.props['vid'])
     hid = self.props['hid'][str(mac)]
     trans_mac.setHid(hid)
     if hid > MAT.reserved:
         # broadcast MAC address
         trans_mac.data[0] = 0xFF
     return trans_mac
Ejemplo n.º 4
0
Archivo: mat.py Proyecto: esnet/enos
 def translate(self, mac):
     if not str(mac) in self.props['hid']:
         with self.props['lock']:
             if not str(mac) in self.props['hid']:
                 hid = random.randint(1, MAT.reserved)
                 while hid in self.props['mac']:
                     hid = random.randint(1, MAT.reserved)
                 self.props['hid'][str(mac)] = hid
                 self.props['mac'][hid] = mac
     trans_mac = MACAddress()
     trans_mac.setSid(self.props['sid'])
     trans_mac.setVid(self.props['vid'])
     hid = self.props['hid'][str(mac)]
     trans_mac.setHid(hid)
     if hid > MAT.reserved:
         # broadcast MAC address
         trans_mac.data[0] = 0xFF
     return trans_mac
Ejemplo n.º 5
0
 def deserialize(obj, net):
     mac = MACAddress(obj['mac'])
     vlan = obj['vlan']
     port = net.builder.portIndex[obj['port']]
     return FlowEntry(mac, vlan, port)
Ejemplo n.º 6
0
    def tryCallback(self, notification):

        """
        And this is the callback itself.  Everything that touches an ODL-specific
        data structure needs to go in here...above this layer it's all generic
        OpenFlow.

        :param notification org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived
        """
        # Find out where the packet came from (ingress port).  First find the node and connector
        # in the ODL/Java world (ingressNode and ingressNodeConnector)
        nodeConnectorRef = notification.getIngress() # XXX need to turn this into a NodeConnector object

        # String nodeId = ingress.getValue().firstIdentifierOf(Node.class).firstKeyOf(Node.class, NodeKey.class).getId().getValue();
        ingressNodeId = nodeConnectorRef.getValue().firstIdentifierOf(Node).firstKeyOf(Node, NodeKey).getId().getValue()
        switch = self.getSwitch(ingressNodeId) # ENOS switch
        ingressNode = self.findODLSwitch(switch) # ODL switch corresponding to it
        # String ncId = ncRef.getValue().firstIdentifierOf(NodeConnector.class).firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue();
        ingressNodeConnectorId = nodeConnectorRef.getValue().firstIdentifierOf(NodeConnector).firstKeyOf(NodeConnector, NodeConnectorKey).getId().getValue()
        # Make sure this is an OpenFlow switch.  If not, ignore the packet.
        if ingressNode.getAugmentation(FlowCapableNode) is not None:

            # This part is harder.  Need to figure out the ENOS port from the
            # NodeConnector object.  We also have the ENOS switch.
            # ingressNodeConnectorId is of the form u'openflow:72620962556436737:3',
            # but we need to get to an ENOS port from that (which has the form "eth13"
            # (for OVS) or "1" (for Corsa).  The ENOS port name for
            # NodeConnectorId can be gotten from the FlowCapableNodeConnector
            # augmentation for the NodeConnector.
            # We iterate over the Node's connectors to try to find the correct
            # NodeConnector...it's sort of the opposite of OdlMdsalImpl.getNodeConnector
            # (and this implies that we should probably make this into a Java function
            # someday.
            # XXX Would replacing this with something that just reads the NodeConnector
            # from the data store be more efficient?  It would avoid the loop, but by time
            # we get here we've already queried the data store for the Node anyway.
            ncs = self.odlMdsalImpl.getNodeConnectors(ingressNode)
            IngressNodeConnector = None
            portName = None
            for nc in ncs:
                if nc.getId().getValue() == ingressNodeConnectorId:
                    IngressNodeConnector = nc
                    fcnc = nc.getAugmentation(FlowCapableNodeConnector)
                    portName = fcnc.getName()
                    break

            # Complain if we can't figure out the ENOS port name
            if portName == None:
                ODLClient.logger.error("Can't determine port name for NodeConnector %r on node %r" % (ingressNodeConnectorId, ingressNodeId))
                return
            if not portName in switch.props['ports']:
                ODLClient.logger.error("Can't find port %s on node %s" % (portName, switch))
                return
            port = switch.props['ports'][portName]
            # Complain if we can't find the port, even though we have its name
            if port == None:
                ODLClient.logger.error("Can't find port %r on node %r" % (portName, ingressNodeId))
                return

            if self.debug and not self.dropLLDP:
                print "PACKET_IN from port %r in node %r" % (port, ingressNodeId)

            # Try to decode the packet.  First get the payload bytes and parse them.
            l2pkt = notification.getPayload()
            ethernetFrame = EthernetFrame.packetToFrame(l2pkt)

            if ethernetFrame != None:

                srcMac = MACAddress(ethernetFrame.getSrcMac())
                destMac = MACAddress(ethernetFrame.getDstMac())
                etherType = ethernetFrame.getEtherType() & 0xffff # convert to unsigned type
                vlanTag = ethernetFrame.getVid()
                payload = ethernetFrame.getPayload()

                # Possibly drop LLDP frames
                if self.dropLLDP:
                    if etherType == EthernetFrame.ETHERTYPE_LLDP:
                        return

                packetIn = PacketInEvent(inPort = port, srcMac=srcMac, dstMac=destMac, vlan=vlanTag, payload=payload)
                packetIn.props['ethertype'] = etherType

                if self.debug:
                    print "  Ethernet frame " + srcMac.str() + " -> " + destMac.str() + " Ethertype " + "%04x" % etherType + " VLAN " + "%04x" % vlanTag
                self.dispatchPacketIn(packetIn)

            else:
                if self.debug:
                    print "  Unknown frame type"

        else:
            if self.debug:
                print "PACKET_IN from Non-OpenFlow Switch"
Ejemplo n.º 7
0
Archivo: vpn.py Proyecto: cygmris/enos
    def packetInCallback(self, dpid, inPort, payload):
        """
        Receive a PACKET_IN callback
        """
        # Decode the callback.  First get the switch
        switch = None
        hexdpid = binascii.hexlify(dpid)
        if hexdpid in self.switchIndex.keys():
            switch = self.switchIndex[hexdpid]
        if switch == None:
            self.logger.error("Can't find switch " + str(dpid))
            return

        # Now find the port
        if inPort not in switch.properties['Ports'].keys():
            self.logger.error("Can't find port " + inPort + " on switch " +
                              switch.resourceName)
            return
        port = Container.fromAnchor(switch.properties['Ports'][inPort])

        frame = EthernetFrame.packetToFrame(payload)
        if frame == None:
            self.logger.error("Cannot parse Ethernet frame")
            return

        switchpopname = switch.properties['Pop']

        # Log the packet we got
        self.logger.info("VpnCallback decode switch " + switch.resourceName +
                         " (" + switchpopname + ") " + " port " + inPort +
                         " vlan " + str(frame.getVid()) + " src " +
                         EthernetFrame.byteString(frame.getSrcMac()) +
                         " dst " +
                         EthernetFrame.byteString(frame.getDstMac()) +
                         " etherType " + hex(frame.getEtherType()))

        # Ignore some packets
        if frame.getEtherType() == EthernetFrame.ETHERTYPE_LLDP:
            self.logger.debug("LLDP frame ignored")
            return

        # Figure out the slice/service ID.  This comes from the mapped destination address
        # (going to be a broadcast address).  If it doesn't match our slice ID then drop.
        # XXX need to check this, not clear if the MACAddress constructor will DTRT.
        mac = MACAddress(frame.getDstMac())
        if (mac.getSid() != self.vpnService.sid):
            self.logger.debug("Destination address doesn't match, ignored")
            return

        # Figure out which VPN (if any) this belongs to
        vpn = None
        vpnsite = None

        # Iterate over all VPNs then all site attachments.
        # If we can match the POP and VLAN, then we've got a match for the site attachments
        # XXX There is probably a more efficient way to do this.
        # XXX Note we can't do any port-based matching because all of the traffic from the
        # hardware switch to the software switch shows up on the same port on the software
        # switch, which is the one generating the PACKET_IN message.

        for (x, v
             ) in MultiPointVPNServiceFactory.getVpnService().vpnIndex.items():
            for (sitename, site) in v.vpnsites.items():
                if site['pop'] == switchpopname and int(
                        v.vpnsitevlans[sitename]) == frame.getVid():
                    vpn = v
                    vpnsite = site
        if vpn == None:
            self.logger.error("Unable to find VPN or site for inbound packet")
            return

        # MAC layer address.  For some reason we don't understand, this needs to be converted from
        # unicode (?!?) to ASCII before we can really use it despite the fact these are all ASCII
        # characters.
        mac = EthernetFrame.byteString(frame.getSrcMac()).encode(
            'ascii', 'ignore')

        self.logger.info("  Source vpn " + vpn.name + " site " +
                         vpnsite['name'] + " src " + mac)
        if vpn.addhostbymac(vpnsite, mac):
            self.logger.info("Added host successfully")
        else:
            self.logger.error("Adding host failed")
        return
Ejemplo n.º 8
0
 def reverse(self, hid):
     if not hid in self.props['mac']:
         return None
     return MACAddress(self.props['mac'][hid])
Ejemplo n.º 9
0
Archivo: vpn.py Proyecto: esnet/enos
    def packetInCallback(self, dpid, inPort, payload):
        """
        Receive a PACKET_IN callback
        """
        # Decode the callback.  First get the switch
        switch = None
        hexdpid = binascii.hexlify(dpid)
        if hexdpid in self.switchIndex.keys():
            switch = self.switchIndex[hexdpid]
        if switch == None:
            self.logger.error("Can't find switch " + str(dpid))
            return

        # Now find the port
        if inPort not in switch.properties['Ports'].keys():
            self.logger.error("Can't find port " + inPort + " on switch " + switch.resourceName)
            return
        port = Container.fromAnchor(switch.properties['Ports'][inPort])

        frame = EthernetFrame.packetToFrame(payload)
        if frame == None:
            self.logger.error("Cannot parse Ethernet frame")
            return

        switchpopname = switch.properties['Pop']

        # Log the packet we got
        self.logger.info("VpnCallback decode switch " + switch.resourceName +
                         " (" + switchpopname + ") " +
                         " port " + inPort + " vlan " + str(frame.getVid()) +
                         " src " + EthernetFrame.byteString(frame.getSrcMac()) +
                         " dst " + EthernetFrame.byteString(frame.getDstMac()) +
                         " etherType " + hex(frame.getEtherType()))

        # Ignore some packets
        if frame.getEtherType() == EthernetFrame.ETHERTYPE_LLDP:
            self.logger.debug("LLDP frame ignored")
            return

        # Figure out the slice/service ID.  This comes from the mapped destination address
        # (going to be a broadcast address).  If it doesn't match our slice ID then drop.
        # XXX need to check this, not clear if the MACAddress constructor will DTRT.
        mac = MACAddress(frame.getDstMac())
        if (mac.getSid() != self.vpnService.sid):
            self.logger.debug("Destination address doesn't match, ignored")
            return

        # Figure out which VPN (if any) this belongs to
        vpn = None
        vpnsite = None

        # Iterate over all VPNs then all site attachments.
        # If we can match the POP and VLAN, then we've got a match for the site attachments
        # XXX There is probably a more efficient way to do this.
        # XXX Note we can't do any port-based matching because all of the traffic from the
        # hardware switch to the software switch shows up on the same port on the software
        # switch, which is the one generating the PACKET_IN message.

        for (x,v) in MultiPointVPNServiceFactory.getVpnService().vpnIndex.items():
            for (sitename,site) in v.vpnsites.items():
                if site['pop'] == switchpopname and int(v.vpnsitevlans[sitename]) == frame.getVid():
                    vpn = v
                    vpnsite = site
        if vpn == None:
            self.logger.error("Unable to find VPN or site for inbound packet")
            return

        # MAC layer address.  For some reason we don't understand, this needs to be converted from
        # unicode (?!?) to ASCII before we can really use it despite the fact these are all ASCII
        # characters.
        mac = EthernetFrame.byteString(frame.getSrcMac()).encode('ascii', 'ignore')

        self.logger.info("  Source vpn " + vpn.name + " site " + vpnsite['name'] + " src " + mac)
        if vpn.addhostbymac(vpnsite, mac):
            self.logger.info("Added host successfully")
        else:
            self.logger.error("Adding host failed")
        return