Exemple #1
0
def nd_advert(vid, eth_src, eth_dst, src_ip, dst_ip):
    """Return IPv6 neighbor avertisement packet.

    Args:
        vid (int or None): VLAN VID to use (or None).
        eth_src (str): source Ethernet MAC address.
        eth_dst (str): destination Ethernet MAC address.
        src_ip (ipaddress.IPv6Address): source IPv6 address.
        dst_ip (ipaddress.IPv6Address): destination IPv6 address.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    pkt = build_pkt_header(
        vid, eth_src, eth_dst, valve_of.ether.ETH_TYPE_IPV6)
    ipv6_icmp6 = ipv6.ipv6(
        src=src_ip,
        dst=dst_ip,
        nxt=valve_of.inet.IPPROTO_ICMPV6,
        hop_limit=IPV6_MAX_HOP_LIM)
    pkt.add_protocol(ipv6_icmp6)
    icmpv6_nd_advert = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_ADVERT,
        data=icmpv6.nd_neighbor(
            dst=src_ip,
            option=icmpv6.nd_option_tla(hw_src=eth_src), res=7))
    pkt.add_protocol(icmpv6_nd_advert)
    pkt.serialize()
    return pkt
Exemple #2
0
    def __init__(self, mac_src, mac_dst, ipv6_src, ipv6_dst, ipv6_tgt):
        """
		================ =========================================================
		Input Parameter  Description
		================ =========================================================
		mac_src			 String instance
		mac_dst			 String instance
		ipv6_src		 String instance
		ipv6_dst		 String instance
		ipv6_tgt		 String instance
		================ =========================================================
		================ =========================================================
		Attribute        Description
		================ =========================================================
		pkt              The Neighbor Solicitation generated packet
		================ =========================================================
		"""
        self.pkt = packet.Packet()

        e = ethernet.ethernet(mac_dst, mac_src, ether.ETH_TYPE_IPV6)
        i6 = ipv6.ipv6(src=ipv6_src, dst=ipv6_dst, nxt=inet.IPPROTO_ICMPV6)
        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_NEIGHBOR_SOLICIT,
            data=icmpv6.nd_neighbor(dst=ipv6_tgt, option=icmpv6.nd_option_sla(hw_src=mac_src)),
        )

        self.pkt.add_protocol(e)
        self.pkt.add_protocol(i6)
        self.pkt.add_protocol(ic)
Exemple #3
0
 def test_init(self):
     nd = icmpv6.nd_neighbor(self.res, self.dst)
     eq_(nd.res >> 29, self.res)
     eq_(nd.dst, self.dst)
     eq_(nd.type_, None)
     eq_(nd.length, None)
     eq_(nd.data, None)
Exemple #4
0
    def __init__(self, mac_src, mac_dst, ipv6_src, ipv6_dst, is_router):
        """
		================ =========================================================
		Input Parameter  Description
		================ =========================================================
		mac_src			 String instance
		mac_dst			 String instance
		ipv6_src		 String instance
		ipv6_dst		 String instance
		is_router		 Boolean instance.
		================ =========================================================
		================ =========================================================
		Attribute        Description
		================ =========================================================
		pkt              The Neighbor Advertisement generated packet
		================ =========================================================
		"""
        self.pkt = packet.Packet()

        e = ethernet.ethernet(mac_dst, mac_src, ether.ETH_TYPE_IPV6)
        i6 = ipv6.ipv6(src=ipv6_src, dst=ipv6_dst, nxt=inet.IPPROTO_ICMPV6)

        if is_router:
            res = 7
        else:
            res = 3

        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_NEIGHBOR_ADVERT,
            data=icmpv6.nd_neighbor(dst=ipv6_src, option=icmpv6.nd_option_tla(hw_src=mac_src), res=res),
        )

        self.pkt.add_protocol(e)
        self.pkt.add_protocol(i6)
        self.pkt.add_protocol(ic)
Exemple #5
0
def nd_reply(eth_src, eth_dst, vid, src_ip, dst_ip, hop_limit):
    """Return IPv6 neighbor discovery reply packet.

    Args:
        eth_src (str): source Ethernet MAC address.
        eth_dst (str): destination Ethernet MAC address.
        vid (int or None): VLAN VID to use (or None).
        src_ip (ipaddr.IPv6Address): source IPv6 address.
        dst_ip (ipaddr.IPv6Address): destination IPv6 address.
        hop_limit (int): IPv6 hop limit.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    pkt = build_pkt_header(
        eth_src, eth_dst, vid, ether.ETH_TYPE_IPV6)
    ipv6_reply = ipv6.ipv6(
        src=src_ip,
        dst=dst_ip,
        nxt=inet.IPPROTO_ICMPV6,
        hop_limit=hop_limit)
    pkt.add_protocol(ipv6_reply)
    icmpv6_reply = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_ADVERT,
        data=icmpv6.nd_neighbor(
            dst=src_ip,
            option=icmpv6.nd_option_tla(hw_src=eth_src), res=7))
    pkt.add_protocol(icmpv6_reply)
    pkt.serialize()
    return pkt
Exemple #6
0
def nd_request(eth_src, vid, src_ip, dst_ip):
    """Return IPv6 neighbor discovery request packet.

    Args:
        eth_src (str): source Ethernet MAC address.
        vid (int or None): VLAN VID to use (or None).
        src_ip (ipaddr.IPv6Address): source IPv6 address.
        dst_ip (ipaddr.IPv6Address): requested IPv6 address.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    nd_mac = ipv6_link_eth_mcast(dst_ip)
    ip_gw_mcast = ipv6_solicited_node_from_ucast(dst_ip)
    pkt = build_pkt_header(eth_src, nd_mac, vid, ether.ETH_TYPE_IPV6)
    ipv6_pkt = ipv6.ipv6(
        src=str(src_ip), dst=ip_gw_mcast, nxt=inet.IPPROTO_ICMPV6)
    pkt.add_protocol(ipv6_pkt)
    icmpv6_pkt = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_SOLICIT,
        data=icmpv6.nd_neighbor(
            dst=dst_ip,
            option=icmpv6.nd_option_sla(hw_src=eth_src)))
    pkt.add_protocol(icmpv6_pkt)
    pkt.serialize()
    return pkt
 def _send_icmp_NS(self, datapath, outport_no, dst_ip):
     src_mac_addr = \
         str(self.dpid_to_switch[datapath.id].ports[outport_no].hw_addr)
     src_ip = \
         str(self.dpid_to_switch[datapath.id].ports[outport_no].gateway.gw_ipv6)
     p = packet.Packet()
     dst_mac, dst_ip_multicast = self._generate_dst_for_NS(dst_ip)
     dst_mac = str(dst_mac)
     dst_ip_multicast = str(dst_ip_multicast)
     dst_ip = str(dst_ip)
     e = ethernet.ethernet(dst = dst_mac, src = src_mac_addr,
             ethertype = ether.ETH_TYPE_IPV6)
     ip6 = ipv6.ipv6(version = 6, traffic_class = 0, flow_label = 0,
             # 4byte ICMP header, 4byte reserved, 16byte target address,
             # 8byte "source link-layer address" option
             # next header value for ICMPv6 is 58
             payload_length = 32, nxt = 58, hop_limit = 255,
             src = src_ip, dst = dst_ip_multicast)
     # source link-layer address
     sla_addr = icmpv6.nd_option_sla(hw_src = src_mac_addr)
     # ns for neighbor solicit; res for reserved, but actually is a flag,
     # see comments on "nd_option_tla" above
     ns = icmpv6.nd_neighbor(res = 4, dst = dst_ip, data = sla_addr)
     ic6 = icmpv6.icmpv6(type_ = icmpv6.ND_NEIGHBOR_SOLICIT, code = 0,
             # checksum = 0 then ryu calculate for you
             csum = 0, data = ns)
     p.add_protocol(e)
     p.add_protocol(ip6)
     p.add_protocol(ic6)
     p.serialize()
     datapath.send_packet_out(in_port = ofproto_v1_0.OFPP_NONE,
         actions = [datapath.ofproto_parser.OFPActionOutput(outport_no)],
         data = p.data)
Exemple #8
0
    def test_to_string(self):
        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
        nd = icmpv6.nd_neighbor(
            self.res, self.dst, self.nd_type, self.nd_length, nd_opt)
        ic = icmpv6.icmpv6(self.type_, self.code, self.csum, nd)

        nd_opt_values = {'hw_src': self.nd_hw_src,
                         'data': None}
        _nd_opt_str = ','.join(['%s=%s' % (k, repr(nd_opt_values[k]))
                                for k, v in inspect.getmembers(nd_opt)
                                if k in nd_opt_values])
        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_la.__name__, _nd_opt_str)

        nd_values = {'res': repr(nd.res),
                     'dst': repr(self.dst),
                     'type_': repr(self.nd_type),
                     'length': repr(self.nd_length),
                     'data': nd_opt_str}
        _nd_str = ','.join(['%s=%s' % (k, nd_values[k])
                            for k, v in inspect.getmembers(nd)
                            if k in nd_values])
        nd_str = '%s(%s)' % (icmpv6.nd_neighbor.__name__, _nd_str)

        icmp_values = {'type_': repr(self.type_),
                       'code': repr(self.code),
                       'csum': repr(self.csum),
                       'data': nd_str}
        _ic_str = ','.join(['%s=%s' % (k, icmp_values[k])
                            for k, v in inspect.getmembers(ic)
                            if k in icmp_values])
        ic_str = '%s(%s)' % (icmpv6.icmpv6.__name__, _ic_str)

        eq_(str(ic), ic_str)
        eq_(repr(ic), ic_str)
Exemple #9
0
def nd_request(vid, eth_src, eth_dst, src_ip, dst_ip):
    """Return IPv6 neighbor discovery request packet.

    Args:
        vid (int or None): VLAN VID to use (or None).
        eth_src (str): source Ethernet MAC address.
        eth_dst (str): Ethernet destination address.
        src_ip (ipaddress.IPv6Address): source IPv6 address.
        dst_ip (ipaddress.IPv6Address): requested IPv6 address.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    if mac_addr_is_unicast(eth_dst):
        nd_mac = eth_dst
        nd_ip = dst_ip
    else:
        nd_mac = ipv6_link_eth_mcast(dst_ip)
        nd_ip = ipv6_solicited_node_from_ucast(dst_ip)
    pkt = build_pkt_header(vid, eth_src, nd_mac, valve_of.ether.ETH_TYPE_IPV6)
    ipv6_pkt = ipv6.ipv6(
        src=str(src_ip), dst=nd_ip, nxt=valve_of.inet.IPPROTO_ICMPV6)
    pkt.add_protocol(ipv6_pkt)
    icmpv6_pkt = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_SOLICIT,
        data=icmpv6.nd_neighbor(
            dst=dst_ip,
            option=icmpv6.nd_option_sla(hw_src=eth_src)))
    pkt.add_protocol(icmpv6_pkt)
    pkt.serialize()
    return pkt
Exemple #10
0
def nd_reply(eth_src, eth_dst, vid, src_ip, dst_ip, hop_limit):
    """Return IPv6 neighbor discovery reply packet.

    Args:
        eth_src (str): source Ethernet MAC address.
        eth_dst (str): destination Ethernet MAC address.
        vid (int or None): VLAN VID to use (or None).
        src_ip (ipaddr.IPv6Address): source IPv6 address.
        dst_ip (ipaddr.IPv6Address): destination IPv6 address.
        hop_limit (int): IPv6 hop limit.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    pkt = build_pkt_header(eth_src, eth_dst, vid, ether.ETH_TYPE_IPV6)
    ipv6_reply = ipv6.ipv6(src=src_ip,
                           dst=dst_ip,
                           nxt=inet.IPPROTO_ICMPV6,
                           hop_limit=hop_limit)
    pkt.add_protocol(ipv6_reply)
    icmpv6_reply = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_ADVERT,
        data=icmpv6.nd_neighbor(dst=src_ip,
                                option=icmpv6.nd_option_tla(hw_src=eth_src),
                                res=7))
    pkt.add_protocol(icmpv6_reply)
    pkt.serialize()
    return pkt
Exemple #11
0
    def test_serialize_with_data(self):
        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
        nd = icmpv6.nd_neighbor(self.res, self.dst, self.nd_type,
                                self.nd_length, nd_opt)
        prev = ipv6(6, 0, 0, 32, 64, 255, self.src_ipv6, self.dst_ipv6)
        nd_csum = icmpv6_csum(prev, self.buf + self.data)

        icmp = icmpv6.icmpv6(self.type_, self.code, 0, nd)
        buf = buffer(icmp.serialize(bytearray(), prev))

        (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
        (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
        (nd_type, nd_length,
         nd_hw_src) = struct.unpack_from('!BB6s', buf,
                                         icmp._MIN_LEN + nd._MIN_LEN)
        data = buf[(icmp._MIN_LEN + nd._MIN_LEN + 8):]

        eq_(type_, self.type_)
        eq_(code, self.code)
        eq_(csum, nd_csum)
        eq_(res >> 29, self.res)
        eq_(dst, self.dst)
        eq_(nd_type, self.nd_type)
        eq_(nd_length, self.nd_length)
        eq_(nd_hw_src, self.nd_hw_src)
Exemple #12
0
def nd_advert(vid, eth_src, eth_dst, src_ip, dst_ip):
    """Return IPv6 neighbor avertisement packet.

    Args:
        vid (int or None): VLAN VID to use (or None).
        eth_src (str): source Ethernet MAC address.
        eth_dst (str): destination Ethernet MAC address.
        src_ip (ipaddress.IPv6Address): source IPv6 address.
        dst_ip (ipaddress.IPv6Address): destination IPv6 address.
    Returns:
        ryu.lib.packet.ethernet: Serialized IPv6 neighbor discovery packet.
    """
    pkt = build_pkt_header(
        vid, eth_src, eth_dst, valve_of.ether.ETH_TYPE_IPV6)
    ipv6_icmp6 = ipv6.ipv6(
        src=src_ip,
        dst=dst_ip,
        nxt=valve_of.inet.IPPROTO_ICMPV6,
        hop_limit=IPV6_MAX_HOP_LIM)
    pkt.add_protocol(ipv6_icmp6)
    icmpv6_nd_advert = icmpv6.icmpv6(
        type_=icmpv6.ND_NEIGHBOR_ADVERT,
        data=icmpv6.nd_neighbor(
            dst=src_ip,
            option=icmpv6.nd_option_tla(hw_src=eth_src), res=7))
    pkt.add_protocol(icmpv6_nd_advert)
    pkt.serialize()
    return pkt
Exemple #13
0
 def test_init(self):
     nd = icmpv6.nd_neighbor(self.res, self.dst)
     eq_(nd.res >> 29, self.res)
     eq_(nd.dst, self.dst)
     eq_(nd.type_, None)
     eq_(nd.length, None)
     eq_(nd.data, None)
Exemple #14
0
	def __init__(self, mac_src, mac_dst, ipv6_src, ipv6_dst, is_router):
		"""
		================ =========================================================
		Input Parameter  Description
		================ =========================================================
		mac_src			 String instance
		mac_dst			 String instance
		ipv6_src		 String instance
		ipv6_dst		 String instance
		is_router		 Boolean instance.
		================ =========================================================
		================ =========================================================
		Attribute        Description
		================ =========================================================
		pkt              The Neighbor Advertisement generated packet
		================ =========================================================
		"""
		self.pkt = packet.Packet()

		e = ethernet.ethernet(mac_dst, mac_src, ether.ETH_TYPE_IPV6)
		i6 = ipv6.ipv6(src = ipv6_src, dst = ipv6_dst, nxt = inet.IPPROTO_ICMPV6)

		if is_router:
			res = 7
		else:
			res = 3

		ic = icmpv6.icmpv6(type_ = icmpv6.ND_NEIGHBOR_ADVERT,
				data = icmpv6.nd_neighbor(dst = ipv6_src, option = icmpv6.nd_option_tla(hw_src = mac_src), res = res))

		self.pkt.add_protocol(e)
		self.pkt.add_protocol(i6)
		self.pkt.add_protocol(ic)
Exemple #15
0
	def __init__(self, mac_src, mac_dst, ipv6_src, ipv6_dst, ipv6_tgt):
		"""
		================ =========================================================
		Input Parameter  Description
		================ =========================================================
		mac_src			 String instance
		mac_dst			 String instance
		ipv6_src		 String instance
		ipv6_dst		 String instance
		ipv6_tgt		 String instance
		================ =========================================================
		================ =========================================================
		Attribute        Description
		================ =========================================================
		pkt              The Neighbor Solicitation generated packet
		================ =========================================================
		"""
		self.pkt = packet.Packet()

		e = ethernet.ethernet(mac_dst, mac_src, ether.ETH_TYPE_IPV6)
		i6 = ipv6.ipv6(src = ipv6_src, dst = ipv6_dst, nxt = inet.IPPROTO_ICMPV6)
		ic = icmpv6.icmpv6(type_ = icmpv6.ND_NEIGHBOR_SOLICIT,
				data = icmpv6.nd_neighbor(dst = ipv6_tgt, option = icmpv6.nd_option_sla(hw_src = mac_src)))

		self.pkt.add_protocol(e)
		self.pkt.add_protocol(i6)
		self.pkt.add_protocol(ic)
Exemple #16
0
    def control_plane_icmpv6_handler(self, in_port, vlan, eth_src,
                                     ipv6_pkt, icmpv6_pkt):
        flowmods = []
        pkt = self.build_ethernet_pkt(
            eth_src, in_port, vlan, ether.ETH_TYPE_IPV6)

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            dst = icmpv6_pkt.data.dst
            ipv6_reply = ipv6.ipv6(
                src=dst,
                dst=ipv6_pkt.src,
                nxt=inet.IPPROTO_ICMPV6,
                hop_limit=ipv6_pkt.hop_limit)
            pkt.add_protocol(ipv6_reply)
            icmpv6_reply = icmpv6.icmpv6(
                type_=icmpv6.ND_NEIGHBOR_ADVERT,
                data=icmpv6.nd_neighbor(
                    dst=dst,
                    option=icmpv6.nd_option_tla(hw_src=self.FAUCET_MAC),
                        res=7))
            pkt.add_protocol(icmpv6_reply)
            pkt.serialize()
            flowmods.extend([self.valve_packetout(in_port, pkt.data)])
        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            resolved_ip_gw = ipaddr.IPv6Address(icmpv6_pkt.data.dst)
            self.logger.info('ND response %s for %s', eth_src, resolved_ip_gw)
            is_updated = None
            if resolved_ip_gw in vlan.nd_cache:
                cached_eth_dst = vlan.nd_cache[resolved_ip_gw].eth_src
                if cached_eth_dst != eth_src:
                    is_updated = True
            else:
                is_updated = False
            for ip_dst, ip_gw in vlan.ipv6_routes.iteritems():
                if ip_gw == resolved_ip_gw:
                    flowmods.extend(
                        self.add_resolved_route(
                            ether.ETH_TYPE_IPV6, vlan, vlan.nd_cache,
                            ip_gw, ip_dst, eth_src,is_updated))
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            dst = ipv6_pkt.dst
            ipv6_reply = ipv6.ipv6(
                src=dst,
                dst=ipv6_pkt.src,
                nxt=inet.IPPROTO_ICMPV6,
                hop_limit=ipv6_pkt.hop_limit)
            pkt.add_protocol(ipv6_reply)
            icmpv6_reply = icmpv6.icmpv6(
                type_=icmpv6.ICMPV6_ECHO_REPLY,
                data=icmpv6.echo(
                    id_=icmpv6_pkt.data.id,
                    seq=icmpv6_pkt.data.seq,
                    data=icmpv6_pkt.data.data))
            pkt.add_protocol(icmpv6_reply)
            pkt.serialize()
            flowmods.extend([self.valve_packetout(in_port, pkt.data)])

        return flowmods
    def test_default_args(self):
        la = icmpv6.nd_option_sla()
        buf = la.serialize()
        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf))

        eq_(res[0], icmpv6.ND_OPTION_SLA)
        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))

        # with nd_neighbor
        prev = ipv6(nxt=inet.IPPROTO_ICMPV6)
        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_NEIGHBOR_ADVERT,
            data=icmpv6.nd_neighbor(
                option=icmpv6.nd_option_tla()))
        prev.serialize(ic, None)
        buf = ic.serialize(bytearray(), prev)
        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))

        eq_(res[0], icmpv6.ND_NEIGHBOR_ADVERT)
        eq_(res[1], 0)
        eq_(res[2], icmpv6_csum(prev, buf))

        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:24]))

        eq_(res[0], 0)
        eq_(res[1], addrconv.ipv6.text_to_bin('::'))

        res = struct.unpack(icmpv6.nd_option_tla._PACK_STR, str(buf[24:]))

        eq_(res[0], icmpv6.ND_OPTION_TLA)
        eq_(res[1], len(icmpv6.nd_option_tla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))

        # with nd_router_solicit
        prev = ipv6(nxt=inet.IPPROTO_ICMPV6)
        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_ROUTER_SOLICIT,
            data=icmpv6.nd_router_solicit(
                option=icmpv6.nd_option_sla()))
        prev.serialize(ic, None)
        buf = ic.serialize(bytearray(), prev)
        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))

        eq_(res[0], icmpv6.ND_ROUTER_SOLICIT)
        eq_(res[1], 0)
        eq_(res[2], icmpv6_csum(prev, buf))

        res = struct.unpack(icmpv6.nd_router_solicit._PACK_STR, str(buf[4:8]))

        eq_(res[0], 0)

        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[8:]))

        eq_(res[0], icmpv6.ND_OPTION_SLA)
        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
    def _send_neighbor_advertisement(self, target_ipv6: str, tun_id: int,
                                     tun_ipv4_dst: str, output_port,
                                     direction):
        """
        Generates the Neighbor Advertisement response packet
        """
        ofproto, parser = self._datapath.ofproto, self._datapath.ofproto_parser

        # Only check direction OUT because direction IN doesn't need tunn info
        if direction == Direction.OUT and (not tun_id or not tun_ipv4_dst):
            self.logger.error("Packet missing tunnel information, can't reply")
            return

        prefix = self.get_custom_prefix(target_ipv6)
        if not prefix:
            self.logger.debug("Can't reply to NS for UE ip %s", target_ipv6)
            return

        pkt = packet.Packet()
        pkt.add_protocol(
            ethernet.ethernet(
                dst=self.MAC_MULTICAST,
                src=self.config.ll_addr,
                ethertype=ether_types.ETH_TYPE_IPV6,
            ))
        pkt.add_protocol(
            ipv6.ipv6(
                dst=self.DEVICE_MULTICAST,
                src=self.config.ipv6_src,
                nxt=in_proto.IPPROTO_ICMPV6,
            ))
        pkt.add_protocol(
            icmpv6.icmpv6(
                type_=icmpv6.ND_NEIGHBOR_ADVERT,
                data=icmpv6.nd_neighbor(
                    dst=target_ipv6,
                    option=icmpv6.nd_option_tla(hw_src=self.config.ll_addr)),
            ))
        pkt.serialize()

        # For NS from SGI response doesn't need tunnel information
        actions_out = []
        if direction == Direction.OUT:
            actions_out.extend([
                parser.NXActionSetTunnel(tun_id=tun_id),
                parser.NXActionRegLoad2(dst='tun_ipv4_dst',
                                        value=tun_ipv4_dst),
            ])
        actions_out.append(parser.OFPActionOutput(port=output_port))
        out = parser.OFPPacketOut(datapath=self._datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions_out,
                                  data=pkt.data)
        ret = self._datapath.send_msg(out)
        if not ret:
            self.logger.error("Datapath disconnected, couldn't send NA")
Exemple #19
0
    def test_default_args(self):
        la = icmpv6.nd_option_sla()
        buf = la.serialize()
        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf))

        eq_(res[0], icmpv6.ND_OPTION_SLA)
        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))

        # with nd_neighbor
        prev = ipv6(nxt=inet.IPPROTO_ICMPV6)
        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_NEIGHBOR_ADVERT,
            data=icmpv6.nd_neighbor(option=icmpv6.nd_option_tla()))
        prev.serialize(ic, None)
        buf = ic.serialize(bytearray(), prev)
        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))

        eq_(res[0], icmpv6.ND_NEIGHBOR_ADVERT)
        eq_(res[1], 0)
        eq_(res[2], icmpv6_csum(prev, buf))

        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:24]))

        eq_(res[0], 0)
        eq_(res[1], addrconv.ipv6.text_to_bin('::'))

        res = struct.unpack(icmpv6.nd_option_tla._PACK_STR, str(buf[24:]))

        eq_(res[0], icmpv6.ND_OPTION_TLA)
        eq_(res[1], len(icmpv6.nd_option_tla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))

        # with nd_router_solicit
        prev = ipv6(nxt=inet.IPPROTO_ICMPV6)
        ic = icmpv6.icmpv6(
            type_=icmpv6.ND_ROUTER_SOLICIT,
            data=icmpv6.nd_router_solicit(option=icmpv6.nd_option_sla()))
        prev.serialize(ic, None)
        buf = ic.serialize(bytearray(), prev)
        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))

        eq_(res[0], icmpv6.ND_ROUTER_SOLICIT)
        eq_(res[1], 0)
        eq_(res[2], icmpv6_csum(prev, buf))

        res = struct.unpack(icmpv6.nd_router_solicit._PACK_STR, str(buf[4:8]))

        eq_(res[0], 0)

        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[8:]))

        eq_(res[0], icmpv6.ND_OPTION_SLA)
        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
Exemple #20
0
def build_pkt(pkt):
    """Build and return a packet and eth type from a dict."""
    layers = []
    assert 'eth_dst' in pkt and 'eth_src' in pkt
    ethertype = None
    if 'arp_source_ip' in pkt and 'arp_target_ip' in pkt:
        ethertype = ether.ETH_TYPE_ARP
        layers.append(
            arp.arp(src_ip=pkt['arp_source_ip'], dst_ip=pkt['arp_target_ip']))
    elif 'ipv6_src' in pkt and 'ipv6_dst' in pkt:
        ethertype = ether.ETH_TYPE_IPV6
        if 'neighbor_solicit_ip' in pkt:
            layers.append(
                icmpv6.icmpv6(
                    type_=icmpv6.ND_NEIGHBOR_SOLICIT,
                    data=icmpv6.nd_neighbor(
                        dst=pkt['neighbor_solicit_ip'],
                        option=icmpv6.nd_option_sla(hw_src=pkt['eth_src']))))
        elif 'echo_request_data' in pkt:
            layers.append(
                icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REQUEST,
                              data=icmpv6.echo(id_=1,
                                               seq=1,
                                               data=pkt['echo_request_data'])))
        layers.append(
            ipv6.ipv6(src=pkt['ipv6_src'],
                      dst=pkt['ipv6_dst'],
                      nxt=inet.IPPROTO_ICMPV6))
    elif 'ipv4_src' in pkt and 'ipv4_dst' in pkt:
        ethertype = ether.ETH_TYPE_IP
        proto = inet.IPPROTO_IP
        if 'echo_request_data' in pkt:
            echo = icmp.echo(id_=1, seq=1, data=pkt['echo_request_data'])
            layers.append(icmp.icmp(type_=icmp.ICMP_ECHO_REQUEST, data=echo))
            proto = inet.IPPROTO_ICMP
        net = ipv4.ipv4(src=pkt['ipv4_src'], dst=pkt['ipv4_dst'], proto=proto)
        layers.append(net)
    assert ethertype is not None, pkt
    if 'vid' in pkt:
        tpid = ether.ETH_TYPE_8021Q
        layers.append(vlan.vlan(vid=pkt['vid'], ethertype=ethertype))
    else:
        tpid = ethertype
    eth = ethernet.ethernet(dst=pkt['eth_dst'],
                            src=pkt['eth_src'],
                            ethertype=tpid)
    layers.append(eth)
    layers = [layer for layer in reversed(layers)]
    result = packet.Packet()
    for layer in layers:
        result.add_protocol(layer)
    result.serialize()
    return (result, ethertype)
Exemple #21
0
    def control_plane_icmpv6_handler(self, in_port, vlan, eth_src,
                                     ipv6_pkt, icmpv6_pkt):
        flowmods = []
        pkt = self.build_ethernet_pkt(
            eth_src, in_port, vlan, ether.ETH_TYPE_IPV6)

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            dst = icmpv6_pkt.data.dst
            ipv6_reply = ipv6.ipv6(
                src=dst,
                dst=ipv6_pkt.src,
                nxt=inet.IPPROTO_ICMPV6,
                hop_limit=ipv6_pkt.hop_limit)
            pkt.add_protocol(ipv6_reply)
            icmpv6_reply = icmpv6.icmpv6(
                type_=icmpv6.ND_NEIGHBOR_ADVERT,
                data=icmpv6.nd_neighbor(
                    dst=dst,
                    option=icmpv6.nd_option_tla(hw_src=self.FAUCET_MAC),
                        res=7))
            pkt.add_protocol(icmpv6_reply)
            pkt.serialize()
            flowmods.extend([self.valve_packetout(in_port, pkt.data)])
        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            resolved_ip_gw = ipaddr.IPv6Address(icmpv6_pkt.data.dst)
            for ip_dst, ip_gw in vlan.ipv6_routes.iteritems():
                if ip_gw == resolved_ip_gw:
                    self.logger.info('ND response %s for %s',
                        eth_src, resolved_ip_gw)
                    flowmods.extend(
                        self.add_resolved_route(
                            ether.ETH_TYPE_IPV6, vlan, vlan.nd_cache,
                            ip_gw, ip_dst, eth_src))
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            dst = ipv6_pkt.dst
            ipv6_reply = ipv6.ipv6(
                src=dst,
                dst=ipv6_pkt.src,
                nxt=inet.IPPROTO_ICMPV6,
                hop_limit=ipv6_pkt.hop_limit)
            pkt.add_protocol(ipv6_reply)
            icmpv6_reply = icmpv6.icmpv6(
                type_=icmpv6.ICMPV6_ECHO_REPLY,
                data=icmpv6.echo(
                    id_=icmpv6_pkt.data.id,
                    seq=icmpv6_pkt.data.seq,
                    data=icmpv6_pkt.data.data))
            pkt.add_protocol(icmpv6_reply)
            pkt.serialize()
            flowmods.extend([self.valve_packetout(in_port, pkt.data)])

        return flowmods
Exemple #22
0
    def test_serialize_without_data(self):
        nd = icmpv6.nd_neighbor(self.res, self.dst)
        prev = ipv6(6, 0, 0, 24, 64, 255, self.src_ipv6, self.dst_ipv6)
        nd_csum = icmpv6_csum(prev, self.buf)

        icmp = icmpv6.icmpv6(self.type_, self.code, 0, nd)
        buf = buffer(icmp.serialize(bytearray(), prev))

        (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
        (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
        data = buf[(icmp._MIN_LEN + nd._MIN_LEN):]

        eq_(type_, self.type_)
        eq_(code, self.code)
        eq_(csum, nd_csum)
        eq_(res >> 29, self.res)
        eq_(dst, self.dst)
        eq_(data, '')
Exemple #23
0
    def test_serialize_without_data(self):
        nd = icmpv6.nd_neighbor(self.res, self.dst)
        prev = ipv6(6, 0, 0, 24, 64, 255, self.src_ipv6, self.dst_ipv6)
        nd_csum = icmpv6_csum(prev, self.buf)

        icmp = icmpv6.icmpv6(self.type_, self.code, 0, nd)
        buf = buffer(icmp.serialize(bytearray(), prev))

        (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
        (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
        data = buf[(icmp._MIN_LEN + nd._MIN_LEN) :]

        eq_(type_, self.type_)
        eq_(code, self.code)
        eq_(csum, nd_csum)
        eq_(res >> 29, self.res)
        eq_(dst, self.dst)
        eq_(data, "")
Exemple #24
0
 def packet_in_handler(self, event):
     if event.msg.match['in_port'] != FAKEPORT:
         return
     pkt = packet.Packet(event.msg.data)
     eth_protocol = pkt.get_protocol(ethernet.ethernet)
     vlan_protocol = pkt.get_protocol(vlan.vlan)
     ipv6_protocol = pkt.get_protocol(ipv6.ipv6)
     icmpv6_protocol = pkt.get_protocol(icmpv6.icmpv6)
     if not (eth_protocol and vlan_protocol and ipv6_protocol
             and icmpv6_protocol):
         return
     if icmpv6_protocol.type_ != icmpv6.ND_NEIGHBOR_SOLICIT:
         return
     if int(ipaddress.ip_address(ipv6_protocol.src)) == 0:
         return
     src_ip = ipaddress.ip_address(icmpv6_protocol.data.dst)
     if src_ip.is_reserved:
         return
     eth_dst = eth_protocol.src
     dst_ip = ipv6_protocol.src
     eth_src = FAKECLIENTMAC
     vid = vlan_protocol.vid
     reply = packet.Packet()
     for protocol in (ethernet.ethernet(eth_dst, eth_src,
                                        ether.ETH_TYPE_8021Q),
                      vlan.vlan(vid=vid, ethertype=ether.ETH_TYPE_IPV6),
                      ipv6.ipv6(src=src_ip,
                                dst=dst_ip,
                                nxt=socket.IPPROTO_ICMPV6,
                                hop_limit=255),
                      icmpv6.icmpv6(
                          type_=icmpv6.ND_NEIGHBOR_ADVERT,
                          data=icmpv6.nd_neighbor(
                              dst=src_ip,
                              option=icmpv6.nd_option_tla(hw_src=eth_src),
                              res=7))):
         reply.add_protocol(protocol)
     reply.serialize()
     out = parser.OFPPacketOut(datapath=event.msg.datapath,
                               buffer_id=ofp.OFP_NO_BUFFER,
                               in_port=ofp.OFPP_CONTROLLER,
                               actions=[parser.OFPActionOutput(FAKEPORT)],
                               data=reply.data)
     self.send_mods(event.msg.datapath, [out])
 def _send_icmp_NS(self, datapath, outport_no, dst_ip):
     src_mac_addr = \
         str(self.dpid_to_switch[datapath.id].ports[outport_no].hw_addr)
     src_ip = \
         str(self.dpid_to_switch[datapath.id].ports[outport_no].gateway.gw_ipv6)
     p = packet.Packet()
     dst_mac, dst_ip_multicast = self._generate_dst_for_NS(dst_ip)
     dst_mac = str(dst_mac)
     dst_ip_multicast = str(dst_ip_multicast)
     dst_ip = str(dst_ip)
     e = ethernet.ethernet(dst=dst_mac,
                           src=src_mac_addr,
                           ethertype=ether.ETH_TYPE_IPV6)
     ip6 = ipv6.ipv6(
         version=6,
         traffic_class=0,
         flow_label=0,
         # 4byte ICMP header, 4byte reserved, 16byte target address,
         # 8byte "source link-layer address" option
         # next header value for ICMPv6 is 58
         payload_length=32,
         nxt=58,
         hop_limit=255,
         src=src_ip,
         dst=dst_ip_multicast)
     # source link-layer address
     sla_addr = icmpv6.nd_option_sla(hw_src=src_mac_addr)
     # ns for neighbor solicit; res for reserved, but actually is a flag,
     # see comments on "nd_option_tla" above
     ns = icmpv6.nd_neighbor(res=4, dst=dst_ip, data=sla_addr)
     ic6 = icmpv6.icmpv6(
         type_=icmpv6.ND_NEIGHBOR_SOLICIT,
         code=0,
         # checksum = 0 then ryu calculate for you
         csum=0,
         data=ns)
     p.add_protocol(e)
     p.add_protocol(ip6)
     p.add_protocol(ic6)
     p.serialize()
     datapath.send_packet_out(
         in_port=ofproto_v1_0.OFPP_NONE,
         actions=[datapath.ofproto_parser.OFPActionOutput(outport_no)],
         data=p.data)
Exemple #26
0
    def test_to_string(self):
        nd_opt = icmpv6.nd_option_tla(self.nd_length, self.nd_hw_src)
        nd = icmpv6.nd_neighbor(self.res, self.dst, nd_opt)
        ic = icmpv6.icmpv6(self.type_, self.code, self.csum, nd)

        nd_opt_values = {
            'length': self.nd_length,
            'hw_src': self.nd_hw_src,
            'data': None
        }
        _nd_opt_str = ','.join([
            '%s=%s' % (k, repr(nd_opt_values[k]))
            for k, v in inspect.getmembers(nd_opt) if k in nd_opt_values
        ])
        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_tla.__name__, _nd_opt_str)

        nd_values = {
            'res': repr(nd.res),
            'dst': repr(self.dst),
            'option': nd_opt_str
        }
        _nd_str = ','.join([
            '%s=%s' % (k, nd_values[k]) for k, v in inspect.getmembers(nd)
            if k in nd_values
        ])
        nd_str = '%s(%s)' % (icmpv6.nd_neighbor.__name__, _nd_str)

        icmp_values = {
            'type_': repr(self.type_),
            'code': repr(self.code),
            'csum': repr(self.csum),
            'data': nd_str
        }
        _ic_str = ','.join([
            '%s=%s' % (k, icmp_values[k]) for k, v in inspect.getmembers(ic)
            if k in icmp_values
        ])
        ic_str = '%s(%s)' % (icmpv6.icmpv6.__name__, _ic_str)

        eq_(str(ic), ic_str)
        eq_(repr(ic), ic_str)
Exemple #27
0
 def nd_solicit_ip_gw(self, ip_gw, controller_ip, vlan, ports):
     flowmods = []
     if ports:
         self.logger.info('Resolving %s', ip_gw)
         nd_mac = self.ipv6_link_eth_mcast(ip_gw)
         ip_gw_mcast = self.ipv6_link_mcast_from_ucast(ip_gw)
         port_num = ports[0].number
         pkt = self.build_ethernet_pkt(
             nd_mac, port_num, vlan, ether.ETH_TYPE_IPV6)
         ipv6_pkt = ipv6.ipv6(
             src=controller_ip.ip, dst=ip_gw_mcast, nxt=inet.IPPROTO_ICMPV6)
         icmpv6_pkt = icmpv6.icmpv6(
             type_=icmpv6.ND_NEIGHBOR_SOLICIT,
             data=icmpv6.nd_neighbor(
                 dst=ip_gw,
                 option=icmpv6.nd_option_sla(hw_src=self.FAUCET_MAC)))
         pkt.add_protocol(ipv6_pkt)
         pkt.add_protocol(icmpv6_pkt)
         pkt.serialize()
         for port in ports:
             flowmods.append(self.valve_packetout(port.number, pkt.data))
     return flowmods
Exemple #28
0
    def test_serialize_with_data(self):
        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
        nd = icmpv6.nd_neighbor(self.res, self.dst, self.nd_type, self.nd_length, nd_opt)
        prev = ipv6(6, 0, 0, 32, 64, 255, self.src_ipv6, self.dst_ipv6)
        nd_csum = icmpv6_csum(prev, self.buf + self.data)

        icmp = icmpv6.icmpv6(self.type_, self.code, 0, nd)
        buf = buffer(icmp.serialize(bytearray(), prev))

        (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
        (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
        (nd_type, nd_length, nd_hw_src) = struct.unpack_from("!BB6s", buf, icmp._MIN_LEN + nd._MIN_LEN)
        data = buf[(icmp._MIN_LEN + nd._MIN_LEN + 8) :]

        eq_(type_, self.type_)
        eq_(code, self.code)
        eq_(csum, nd_csum)
        eq_(res >> 29, self.res)
        eq_(dst, self.dst)
        eq_(nd_type, self.nd_type)
        eq_(nd_length, self.nd_length)
        eq_(nd_hw_src, self.nd_hw_src)
Exemple #29
0
 def nd_solicit_ip_gw(self, ip_gw, controller_ip, vlan, ports):
     flowmods = []
     if ports:
         self.logger.info('Resolving %s', ip_gw)
         nd_mac = self.ipv6_link_eth_mcast(ip_gw)
         ip_gw_mcast = self.ipv6_link_mcast_from_ucast(ip_gw)
         port_num = ports[0].number
         pkt = self.build_ethernet_pkt(
             nd_mac, port_num, vlan, ether.ETH_TYPE_IPV6)
         ipv6_pkt = ipv6.ipv6(
             src=controller_ip.ip, dst=ip_gw_mcast, nxt=inet.IPPROTO_ICMPV6)
         icmpv6_pkt = icmpv6.icmpv6(
             type_=icmpv6.ND_NEIGHBOR_SOLICIT,
             data=icmpv6.nd_neighbor(
                 dst=ip_gw,
                 option=icmpv6.nd_option_sla(hw_src=self.FAUCET_MAC)))
         pkt.add_protocol(ipv6_pkt)
         pkt.add_protocol(icmpv6_pkt)
         pkt.serialize()
         for port in ports:
             flowmods.append(self.valve_packetout(port.number, pkt.data))
     return flowmods
Exemple #30
0
    def test_smoke_packet_in(self):
        nd_solicit = packet.Packet()
        eth_src = '01:02:03:04:05:06'
        eth_dst = 'ff:ff:ff:ff:ff:ff'
        src_ip = 'fc00::1'
        dst_ip = 'fc00::2'
        vid = 2
        for protocol in (
                ethernet.ethernet(eth_dst, eth_src, ether.ETH_TYPE_8021Q),
                vlan.vlan(vid=vid, ethertype=ether.ETH_TYPE_IPV6),
                ipv6.ipv6(src=src_ip, dst=dst_ip, nxt=socket.IPPROTO_ICMPV6, hop_limit=255),
                icmpv6.icmpv6(
                    type_=icmpv6.ND_NEIGHBOR_SOLICIT,
                    data=icmpv6.nd_neighbor(dst=src_ip, option=icmpv6.nd_option_tla(hw_src=eth_src), res=7))):
            nd_solicit.add_protocol(protocol)
        nd_solicit.serialize()


        fake_dp = FakeDP()
        fake_pipette = Pipette(dpset={})

        class FakeMsg:

            def __init__(self):
                self.datapath = fake_dp
                self.match = {'in_port': FAKEPORT}
                self.data = nd_solicit.data


        class FakePiEv:

            def __init__(self):
                self.msg = FakeMsg()


        fake_pipette = Pipette(dpset={})
        fake_pipette.packet_in_handler(FakePiEv())
        assert fake_dp.msgs
    def _handle_icmpv6(self, msg, pkt, icmpv6_pkt):
        #print 'icmpv6', icmpv6_pkt

        switch = self.dpid_to_switch[msg.datapath.id]
        in_port_no = msg.in_port

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            gateway = switch.ports[in_port_no].gateway
            pop_list = []
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            if gateway and gateway.gw_ipv6 == ipv6_pkt.dst:
                self._remember_mac_addr(switch, pkt, 6)
                for i in xrange(len(switch.msg_buffer)):
                    msg, pkt, outport_no, _4or6 = switch.msg_buffer[i]
                    if self.last_switch_out(msg, pkt, outport_no, _4or6):
                        pop_list.append(i)

                pop_list.sort(reverse = True)
                for i in pop_list:
                    switch.msg_buffer.pop(i)

                return True
            return False

        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            port = switch.ports[in_port_no]
            if port.gateway and icmpv6_pkt.data.dst != port.gateway.gw_ipv6:
                print convert.bin_to_ipv6(icmpv6_pkt.data.dst)
                print convert.bin_to_ipv6(port.gateway.gw_ipv6)
                return False
            #send a ND_NEIGHBOR_REPLY packet
            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = port.hw_addr
            e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IPV6)
            ic6_data_data = icmpv6.nd_option_la(hw_src=ether_src, data=None)
            #res = 3 or 7
            ic6_data = icmpv6.nd_neighbor(res=3,dst=icmpv6_pkt.data.dst,
                    type_=icmpv6.nd_neighbor.ND_OPTION_TLA,length=1,
                    data=ic6_data_data)
            ic6 = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT,code=0,
                    csum=0,data=ic6_data)
            #payload_length
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            i6 = ipv6.ipv6(version= 6,traffic_class=0,flow_label=0,
                    payload_length=32,nxt=58,hop_limit=255,
                    src=icmpv6_pkt.data.dst,dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,
                    actions=
                        [datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                    data=p.data)
            print 'send a NA packet'
            return True
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            ipv6_pkt = self.find_packet(pkt, 'ipv6')

            need_reply = False
            for _k, p in switch.ports.iteritems():
                if p.gateway and p.gateway.gw_ipv6 == ipv6_pkt.dst:
                    need_reply = True
                    break
            if not need_reply:
                return False

            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = switch.ports[in_port_no].hw_addr
            e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IPV6)
            ic6_data = icmpv6_pkt.data
            ic6 = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY,code=0,
                                csum=0,data=ic6_data)
            i6 = ipv6.ipv6(version= 6,traffic_class=0,flow_label=0,
                            payload_length=64,nxt=58,hop_limit=64,
                            src=ipv6_pkt.dst,dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,
                    actions=
                        [datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                    data=p.data)
            print 'send a ping6 reply packet'
            return True

        return False
    def _packet_in_handler(self, ev):
        #print("===============NEW PACKET===============")
        
        # If you hit this you might want to increase 
        # the "miss_send_length" of your switch
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",ev.msg.msg_len, ev.msg.total_len)

        #Extracting Message informations
        #Topology stuff
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        #Protocol stuff
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        dst = eth.dst
        src = eth.src

        i = pkt.get_protocol(ipv6)
        #if it's not related to IPV6, not considered
        if i is None:
            #Here you can get lldp packets
           return 0
        print("------------IPV6 PACKET------------")
        
        if(self.RoutingDone==False):
            #If it's the first ipv6 packet received routing must be done before
            self.collectRoutingInfo()

        pkt_type =0         
        dpid = datapath.id
        print 'DPID::{}'.format(dpid)
        
        #Examining protocols in the IP packet
        for p in pkt.protocols:
            #Handling icmpv6 packets
            if p.protocol_name == 'icmpv6':
                pkt_type=1
            if pkt_type == 1:
                print("-----------------ICMPv6-----------------")	
                icmp = pkt.get_protocols(icmpv6.icmpv6)[0]
                itype = 0
                found = 0
                prefix =''
                if icmp.type_== 133:
                    print 'Type : Router Solicitation'
                    itype = 1
                elif icmp.type_== 134:
                    print 'Type : Router Advertisement'
                    itype = 2
                elif icmp.type_== 128:
                    print 'Type : Echo Request'
                    itype = 4
                elif icmp.type_== 129:
                    print 'Type : Echo Reply'
                    itype = 5
                elif icmp.type_ ==136:
                    print 'Type : Neighbour Advertisement'
                    itype=3
                elif icmp.type_ ==135:
                    print'Type : Neighbour Solicitation'
                    itype=6
                else:
                    print 'Type : other ICMPV6 message'
                    print (icmp.type_)

        
        #mac_to_port is not used 
        self.mac_to_port.setdefault(dpid, {})
        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
        print("Details : packet in ", dpid, src, dst, in_port)
       

        #once protocols are known, it's time to prepare answers
 
        #temporary solution : here no authentication protocol
        #every user are granted
        found=1
        
        #In case of Router Sollicitation
        if((itype == 1)&(found == 1)):
            
            #Mobility Management Procedure is fired
            
            #Asking for the list of the prior network
            #And updating it with the current one
            #host ID based on MAC address
            #the currrent datapath is also provided
            priorNetworks = self.mobTracker.getTraceAndUpdate(src,datapath);
            print('~~~~~~~~~~NODE HAS REGISTERED~~~~~~~~~~')
            print('previous networks : ')
            print (priorNetworks)
            print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
            #if the list is empty there is nothing more to do
            #if not tunnels must be set up:
            if priorNetworks is not None:
                
                #creating tunnels with all the previous network and the current one
                for priorDp in priorNetworks[:-1]:
                    #Getting new tunnel identifier
                    tunID = self.tunnelID
                    self.tunnelID += 1
                    #set up tunnel, host MAC @ is considered as identifier
                    self.setUpTunnel(src,priorDp,datapath,tunID)

            #once flows are set up, router advertisement has to be sent
            #create RA including the allocated prefix (should consider multiple prefixes later) 
            #direct reply on the incomming switch port
            out_port = in_port 
            pkt_generated = packet.Packet()
            e= ethernet.ethernet(dst=str(eth.src),src=self.generateMAC(dpid,in_port), ethertype=ether.ETH_TYPE_IPV6)
    
            #AS IT IS A REPLY TO ROUTER SOLLICITATION : SOURCE @ MUST BE LOCAL SCOPE!!
            srcIP = self.generateLL(dpid,in_port)
            ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=srcIP, dst=str(i.src))
            #setting up prefix : the dependant Local Network prefix is returned
            prefix = '200'+str(dpid)+'::1'            
            icmp_v6 = icmpv6.icmpv6(type_=icmpv6.ND_ROUTER_ADVERT, data=icmpv6.nd_router_advert(ch_l=64, rou_l=4, options=[icmpv6.nd_option_pi(length=4, pl=64, res1=7, val_l=86400, pre_l=14400, prefix=prefix)]))
            pkt_generated.add_protocol(e)
            pkt_generated.add_protocol(ip)
            pkt_generated.add_protocol(icmp_v6)
            pkt_generated.serialize()
            actions = [parser.OFPActionOutput(out_port)]	
            out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
            datapath.send_msg(out_ra)
            print('>>>>>>>>>> ROUTER ADVERTISEMENT SENT <<<<<<<<<<')
            return
        
        #handling neighbour solicitation
        elif itype==6:
            neighSol = pkt.get_protocols(icmpv6.icmpv6)[0]
            print (neighSol)
            opt = neighSol.data.option
            trg = neighSol.data.dst
            
            if opt is not None :
            #if opt is not None, the NS is for getting the MAC @ of a given IP @
                if isinstance(opt,ryu.lib.packet.icmpv6.nd_option_sla):
                #link layer address request

                    #check if the solicited @ is the one of the router 
                    trgPort = None
                    for localPort in range(1,len(self.switchList)+1):
                        if str(trg)==(self.bindingList[dpid,localPort]):
                            trgPort = localPort
                            break;
                    #if the request concerns the router, prepare answer:
                    if localPort is not None :
                        #get hw@
                        hw_addr = opt.hw_src
                        #reply with a neighbor adv
                        neigh_adv = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT, data=icmpv6.nd_neighbor(res=7, dst=str(trg), option=icmpv6.nd_option_tla(hw_src=self.generateMAC(dpid,localPort))))
                        e= ethernet.ethernet(dst=str(hw_addr),src=self.generateMAC(dpid,in_port), ethertype=ether.ETH_TYPE_IPV6)
                        #here reply with global scope @
                        srcIP = self.bindingList[dpid,in_port]
                        ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=srcIP, dst=str(i.src))
                        
                        #direct reply on the incomming switch port
                        out_port = in_port 
                        pkt_generated = packet.Packet()

                    
                        pkt_generated.add_protocol(e)
                        pkt_generated.add_protocol(ip)
                        pkt_generated.add_protocol(neigh_adv)
                        pkt_generated.serialize()

                        #TODO : think about the flow to set up
                        # MATCH : router sollicitation for one of the local @:
                        #creat tuple with all the local @ :
                        # listTemp=[]
                        # for i in range(1,len(self.switchList)):
                        #     listTemp.append.(self.bindingList[dpid,i])
                        # tupleLocalAdd =  tuple(listTemp)
                        # matchs = [parser.OFPMatch(icmpv6_type=135,ipv6_nd_target=tupleLocalAdd)]
                        

                        #ACTION : the NA must be forwarded on the incomming switch port
                        
                        actions = [parser.OFPActionOutput(out_port)]	
                        out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
                        datapath.send_msg(out_ra)
                        print('..........neighbor advertisement sent..........')
                       
            else:
                print('conflict resolution')
                
                #if option is None, the NS is sent for conflict resolution :
                #we store the annouced MAC the global dict. if they are new 
                if trg[0:4] != 'fe80' :
                    #registering globlal @
                    lst = [eth.src,trg]
                    if lst not in self.coveredHosts[dpid]:
                        #the couple is added only if it's a new one
                        self.coveredHosts[dpid].append(lst)
                        print ('registered hosts', self.coveredHosts)
                    #otherwise nothing to do

        #handling ping requests and reply
        elif itype == 4 or itype == 5:
            #looking at destination address, finding out which is the next hope, changing MAC @ 
            ping_src = i.src
            ping_dst = i.dst
            echo = pkt.get_protocols(icmpv6.icmpv6)[0];
            print(echo)
            
            #when ip dst @ is known : 3 cases:

            #destination is behind another router
            #destination is behind the current router
            #destination is the current router 
            
            #fetching all the local addresses of the current switch
            localAddressesList = []
            for localPort in range(1,len(self.switchList)+1):
                localAddressesList.append(self.bindingList[dpid,localPort])
           
            if ping_dst in localAddressesList :
                print('ping addressed to the router')
                #the ping is addressed to the switch:
                #!!!! not really working only with local network interfaces
                #!!!!not working with backbones interfaces!!!
                #if it's a request : reply
                if itype == 4:
                    #copy request data into the reply
                    reqData = echo.data
                    pingReply = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY, data=reqData)
                    #direct reply on the incomming switch port
                    out_port = in_port 

                    e= ethernet.ethernet(dst=src,src=dst, ethertype=ether.ETH_TYPE_IPV6)
                    #here reply with global scope @
                    ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=str(ping_dst), dst=str(ping_src))
                    pkt_generated = packet.Packet()

                    pkt_generated.add_protocol(e)
                    pkt_generated.add_protocol(ip)
                    pkt_generated.add_protocol(pingReply)
                    print('.........................')
                    print(pkt_generated)
                    pkt_generated.serialize()
                    #ACTION : the NA must be forwarded on the incomming switch port
                    actions = [parser.OFPActionOutput(out_port)]
                    
                    out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
                    datapath.send_msg(out_ra)
                    #TODO Flow to set up...
                    print('..........Ping Reply sent..........')
                    
            else:
                print('ping another host or switch received by ', dpid, 'going to', ping_dst)

                #TODO : handle ping to backbone interface of a distant router
                
                #pinging switches interfaces
                # for localPort in range(2,len(self.switchList)):
                #     match = parser.OFPMatch(ipv6_dst=(self.bindingList[dpid,localPort]))
                #     action = [parser.OFPActionOutput(localPort)]
                #     self.add_flow(datapath, 1, match, action)
             
                #pinging hosts
                for dp_ID in range(1,len(self.switchList)+1):
                    if ping_dst[0:4]==self.bindingList[dp_ID,1][0:4]:
                        print ('ping going to ', ping_dst , ' must be routed to ', str(dp_ID) ,' as localNW domain is ', self.bindingList[dp_ID,1])
                        break
                #handle the case where no sub domain is found
                else:
                    print ('no subdomain found deleting packet')
                    #throw exception
                    return 0
                
                print(self.bindingList[dp_ID,1][0:4])
                if dp_ID == dpid:#PING GOING TO LOCAL NETWORK
                    outputIntf = 1
                    print('ping toward local network')
                    #setting new addresses MAC:
                    new_mac_src = self.generateMAC(dpid,1)
                    for idx,host in enumerate(self.coveredHosts[dpid]):
                        if host[1] == ping_dst:
                            new_mac_dst = self.coveredHosts[dpid][idx][0]
                            break
                    else:
                        print ('host unknown is the subdomain deleting packet')
                         #throw exception
                else:#PING GOING OUTSIDE LOCAL NETWORK
                    outputIntf = self.routing(dpid,dp_ID)
                    new_mac_src = self.generateMAC(dpid,outputIntf)
                    new_mac_dst = self.generateMAC(dp_ID,self.routing(dp_ID,dpid))
                    print ('ping toward neighbor ', outputIntf)
                        
                action = [parser.OFPActionDecNwTtl(), parser.OFPActionSetField(eth_src=new_mac_src),
                          parser.OFPActionSetField(eth_dst=new_mac_dst),parser.OFPActionOutput(outputIntf) ]
            
                match = parser.OFPMatch( eth_type=0x86dd, ip_proto=58, ipv6_dst=(ping_dst,'ffff:ffff:ffff:ffff::'))
                print('ready to push flow to ',datapath)
                self.add_flow(datapath, 1, match, action)
                print('flow pushed')        
                
                

        else:
            print ('')
            print("========================================")            
Exemple #33
0
    def _packet_in_handler(self, ev):
        #print("===============NEW PACKET===============")

        # If you hit this you might want to increase
        # the "miss_send_length" of your switch
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",
                              ev.msg.msg_len, ev.msg.total_len)

        #Extracting Message informations
        #Topology stuff
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        #Protocol stuff
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        dst = eth.dst
        src = eth.src

        i = pkt.get_protocol(ipv6)
        #if it's not related to IPV6, not considered
        if i is None:
            #Here you can get lldp packets
            return 0
        print("------------IPV6 PACKET------------")

        if (self.RoutingDone == False):
            #If it's the first ipv6 packet received routing must be done before
            self.collectRoutingInfo()

        pkt_type = 0
        dpid = datapath.id
        print 'DPID::{}'.format(dpid)

        #Examining protocols in the IP packet
        for p in pkt.protocols:
            #Handling icmpv6 packets
            if p.protocol_name == 'icmpv6':
                pkt_type = 1
            if pkt_type == 1:
                print("-----------------ICMPv6-----------------")
                icmp = pkt.get_protocols(icmpv6.icmpv6)[0]
                itype = 0
                found = 0
                prefix = ''
                if icmp.type_ == 133:
                    print 'Type : Router Solicitation'
                    itype = 1
                elif icmp.type_ == 134:
                    print 'Type : Router Advertisement'
                    itype = 2
                elif icmp.type_ == 128:
                    print 'Type : Echo Request'
                    itype = 4
                elif icmp.type_ == 129:
                    print 'Type : Echo Reply'
                    itype = 5
                elif icmp.type_ == 136:
                    print 'Type : Neighbour Advertisement'
                    itype = 3
                elif icmp.type_ == 135:
                    print 'Type : Neighbour Solicitation'
                    itype = 6
                else:
                    print 'Type : other ICMPV6 message'
                    print(icmp.type_)

        #mac_to_port is not used
        self.mac_to_port.setdefault(dpid, {})
        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
        print("Details : packet in ", dpid, src, dst, in_port)

        #once protocols are known, it's time to prepare answers

        #temporary solution : here no authentication protocol
        #every user are granted
        found = 1

        #In case of Router Sollicitation
        if ((itype == 1) & (found == 1)):

            #Mobility Management Procedure is fired

            #Asking for the list of the prior network
            #And updating it with the current one
            #host ID based on MAC address
            #the currrent datapath is also provided
            priorNetworks = self.mobTracker.getTraceAndUpdate(src, datapath)
            print('~~~~~~~~~~NODE HAS REGISTERED~~~~~~~~~~')
            print('previous networks : ')
            print(priorNetworks)
            print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
            #if the list is empty there is nothing more to do
            #if not tunnels must be set up:
            if priorNetworks is not None:
                #maintaining a list in order to know when to stop in the tunnel creation/updating
                #and in order not to create a tunnel that will be updated in the same procedure
                updatedTunnels = []
                #creating tunnels with all the previous network and the current one
                for priorDp in priorNetworks[:-1]:

                    #Getting new tunnel identifier, a tunnelID is build with
                    #the concatenation of the old router ID and the new router ID
                    tunID = int(str(priorDp.id) + str(datapath.id))
                    #when a already updated tunnel is met, it is skipped
                    if tunID in updatedTunnels:
                        continue
                    #else it's registered to the list and the procedure is launched
                    updatedTunnels.append(tunID)

                    if priorDp.id != datapath.id:
                        #set up tunnel, host MAC @ is considered as identifier
                        self.setUpTunnel(src, priorDp, datapath, tunID)
                    else:
                        #if the network is back in a previously visited network
                        #redirect the tunneled flow on the local interface
                        priorPrefix = str('200') + str(priorDp.id)
                        priorAddress = self.forgeHostGlobalIP(src, priorPrefix)
                        matchBack = datapath.ofproto_parser.OFPMatch(
                            eth_type=0x86dd,
                            ip_proto=58,
                            ipv6_dst=(
                                priorAddress,
                                'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))
                        new_mac_src = self.generateMAC(priorDp.id, 1)
                        new_mac_dst = src
                        actionsBack = [
                            datapath.ofproto_parser.OFPActionDecNwTtl(),
                            datapath.ofproto_parser.OFPActionSetField(
                                eth_src=new_mac_src),
                            datapath.ofproto_parser.OFPActionSetField(
                                eth_dst=new_mac_dst),
                            datapath.ofproto_parser.OFPActionOutput(1)
                        ]
                        self.add_flow(datapath, 65535, matchBack, actionsBack)

            #once flows are set up, router advertisement has to be sent
            #create RA including the allocated prefix (should consider multiple prefixes later)
            #direct reply on the incomming switch port
            out_port = in_port
            pkt_generated = packet.Packet()
            e = ethernet.ethernet(dst=str(eth.src),
                                  src=self.generateMAC(dpid, in_port),
                                  ethertype=ether.ETH_TYPE_IPV6)

            #AS IT IS A REPLY TO ROUTER SOLLICITATION : SOURCE @ MUST BE LOCAL SCOPE!!
            srcIP = self.generateLL(dpid, in_port)
            ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=srcIP, dst=str(i.src))
            #setting up prefix : the dependant Local Network prefix is returned
            prefix = '200' + str(dpid) + '::1'
            icmp_v6 = icmpv6.icmpv6(type_=icmpv6.ND_ROUTER_ADVERT,
                                    data=icmpv6.nd_router_advert(
                                        ch_l=64,
                                        rou_l=4,
                                        options=[
                                            icmpv6.nd_option_pi(length=4,
                                                                pl=64,
                                                                res1=7,
                                                                val_l=86400,
                                                                pre_l=14400,
                                                                prefix=prefix)
                                        ]))
            pkt_generated.add_protocol(e)
            pkt_generated.add_protocol(ip)
            pkt_generated.add_protocol(icmp_v6)
            pkt_generated.serialize()
            actions = [parser.OFPActionOutput(out_port)]
            out_ra = parser.OFPPacketOut(datapath=datapath,
                                         buffer_id=ofproto.OFP_NO_BUFFER,
                                         in_port=0,
                                         actions=actions,
                                         data=pkt_generated.data)
            datapath.send_msg(out_ra)
            print('>>>>>>>>>> ROUTER ADVERTISEMENT SENT <<<<<<<<<<')
            return

        #handling neighbour solicitation
        elif itype == 6:
            neighSol = pkt.get_protocols(icmpv6.icmpv6)[0]
            print(neighSol)
            opt = neighSol.data.option
            trg = neighSol.data.dst

            if opt is not None:
                #if opt is not None, the NS is for getting the MAC @ of a given IP @
                if isinstance(opt, ryu.lib.packet.icmpv6.nd_option_sla):
                    #link layer address request

                    #check if the solicited @ is the one of the router
                    trgPort = None
                    for localPort in range(1, len(self.switchList) + 1):
                        if str(trg) == (self.bindingList[dpid, localPort]):
                            trgPort = localPort
                            break
                    #if the request concerns the router, prepare answer:
                    if localPort is not None:
                        #get hw@
                        hw_addr = opt.hw_src
                        #reply with a neighbor adv
                        neigh_adv = icmpv6.icmpv6(
                            type_=icmpv6.ND_NEIGHBOR_ADVERT,
                            data=icmpv6.nd_neighbor(
                                res=7,
                                dst=str(trg),
                                option=icmpv6.nd_option_tla(
                                    hw_src=self.generateMAC(dpid, localPort))))
                        e = ethernet.ethernet(dst=str(hw_addr),
                                              src=self.generateMAC(
                                                  dpid, in_port),
                                              ethertype=ether.ETH_TYPE_IPV6)
                        #here reply with global scope @
                        srcIP = self.bindingList[dpid, in_port]
                        ip = ipv6(nxt=inet.IPPROTO_ICMPV6,
                                  src=srcIP,
                                  dst=str(i.src))

                        #direct reply on the incomming switch port
                        out_port = in_port
                        pkt_generated = packet.Packet()

                        pkt_generated.add_protocol(e)
                        pkt_generated.add_protocol(ip)
                        pkt_generated.add_protocol(neigh_adv)
                        pkt_generated.serialize()

                        #TODO : think about the flow to set up
                        # MATCH : router sollicitation for one of the local @:
                        #creat tuple with all the local @ :
                        # listTemp=[]
                        # for i in range(1,len(self.switchList)):
                        #     listTemp.append.(self.bindingList[dpid,i])
                        # tupleLocalAdd =  tuple(listTemp)
                        # matchs = [parser.OFPMatch(icmpv6_type=135,ipv6_nd_target=tupleLocalAdd)]

                        #ACTION : the NA must be forwarded on the incomming switch port

                        actions = [parser.OFPActionOutput(out_port)]
                        out_ra = parser.OFPPacketOut(
                            datapath=datapath,
                            buffer_id=ofproto.OFP_NO_BUFFER,
                            in_port=0,
                            actions=actions,
                            data=pkt_generated.data)
                        datapath.send_msg(out_ra)
                        print(
                            '..........neighbor advertisement sent..........')

            else:
                print('conflict resolution')

                #if option is None, the NS is sent for conflict resolution :
                #we store the annouced MAC the global dict. if they are new
                if trg[0:4] != 'fe80':
                    #registering globlal @
                    lst = [eth.src, trg]
                    if lst not in self.coveredHosts[dpid]:
                        #the couple is added only if it's a new one
                        self.coveredHosts[dpid].append(lst)
                        print('registered hosts', self.coveredHosts)
                    #otherwise nothing to do

        #handling ping requests and reply
        elif itype == 4 or itype == 5:
            #looking at destination address, finding out which is the next hope, changing MAC @
            ping_src = i.src
            ping_dst = i.dst
            echo = pkt.get_protocols(icmpv6.icmpv6)[0]
            print(echo)

            #when ip dst @ is known : 3 cases:

            #destination is behind another router
            #destination is behind the current router
            #destination is the current router

            #fetching all the local addresses of the current switch
            localAddressesList = []
            for localPort in range(1, len(self.switchList) + 1):
                localAddressesList.append(self.bindingList[dpid, localPort])

            if ping_dst in localAddressesList:
                print('ping addressed to the router')
                #the ping is addressed to the switch:
                #!!!! not really working only with local network interfaces
                #!!!!not working with backbones interfaces!!!
                #if it's a request : reply
                if itype == 4:
                    #copy request data into the reply
                    reqData = echo.data
                    pingReply = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY,
                                              data=reqData)
                    #direct reply on the incomming switch port
                    out_port = in_port

                    e = ethernet.ethernet(dst=src,
                                          src=dst,
                                          ethertype=ether.ETH_TYPE_IPV6)
                    #here reply with global scope @
                    ip = ipv6(nxt=inet.IPPROTO_ICMPV6,
                              src=str(ping_dst),
                              dst=str(ping_src))
                    pkt_generated = packet.Packet()

                    pkt_generated.add_protocol(e)
                    pkt_generated.add_protocol(ip)
                    pkt_generated.add_protocol(pingReply)
                    print('.........................')
                    print(pkt_generated)
                    pkt_generated.serialize()
                    #ACTION : the NA must be forwarded on the incomming switch port
                    actions = [parser.OFPActionOutput(out_port)]

                    out_ra = parser.OFPPacketOut(
                        datapath=datapath,
                        buffer_id=ofproto.OFP_NO_BUFFER,
                        in_port=0,
                        actions=actions,
                        data=pkt_generated.data)
                    datapath.send_msg(out_ra)
                    #TODO Flow to set up...
                    print('..........Ping Reply sent..........')

            else:
                print('ping another host or switch received by ', dpid,
                      'going to', ping_dst)

                #TODO : handle ping to backbone interface of a distant router

                #pinging switches interfaces
                # for localPort in range(2,len(self.switchList)):
                #     match = parser.OFPMatch(ipv6_dst=(self.bindingList[dpid,localPort]))
                #     action = [parser.OFPActionOutput(localPort)]
                #     self.add_flow(datapath, 1, match, action)

                #pinging hosts
                for dp_ID in range(1, len(self.switchList) + 1):
                    if ping_dst[0:4] == self.bindingList[dp_ID, 1][0:4]:
                        print('ping going to ', ping_dst,
                              ' must be routed to ', str(dp_ID),
                              ' as localNW domain is ', self.bindingList[dp_ID,
                                                                         1])
                        break
                #handle the case where no sub domain is found
                else:
                    print('no subdomain found deleting packet')
                    #throw exception
                    return 0

                print(self.bindingList[dp_ID, 1][0:4])
                if dp_ID == dpid:  #PING GOING TO LOCAL NETWORK
                    outputIntf = 1
                    print('ping toward local network')
                    #setting new addresses MAC:
                    new_mac_src = self.generateMAC(dpid, 1)
                    for idx, host in enumerate(self.coveredHosts[dpid]):
                        if host[1] == ping_dst:
                            new_mac_dst = self.coveredHosts[dpid][idx][0]
                            break
                    else:
                        print('host unknown is the subdomain deleting packet')
                        #throw exception
                else:  #PING GOING OUTSIDE LOCAL NETWORK
                    outputIntf = self.routing(dpid, dp_ID)
                    new_mac_src = self.generateMAC(dpid, outputIntf)
                    new_mac_dst = self.generateMAC(dp_ID,
                                                   self.routing(dp_ID, dpid))
                    print('ping toward neighbor ', outputIntf)

                action = [
                    parser.OFPActionDecNwTtl(),
                    parser.OFPActionSetField(eth_src=new_mac_src),
                    parser.OFPActionSetField(eth_dst=new_mac_dst),
                    parser.OFPActionOutput(outputIntf)
                ]

                match = parser.OFPMatch(eth_type=0x86dd,
                                        ip_proto=58,
                                        ipv6_dst=(ping_dst,
                                                  'ffff:ffff:ffff:ffff::'))
                print('ready to push flow to ', datapath)
                #routing related flow then pushed to table 1
                self.add_flow(datapath, 1, match, action, tblId=1)
                print('flow pushed')

        else:
            print('')
            print("========================================")
Exemple #34
0
    def _packet_in_handler(self, ev):
        msg = ev.msg
        in_port  = msg.in_port
        datapath = msg.datapath
        ofproto = datapath.ofproto
        dpid = datapath.id
        print 'mac_to_port',self.mac_to_port,'\n'       
        self.mac_to_port.setdefault(dpid, {})
        print 'mac_to_port',self.mac_to_port,'\n'
       
        dst, src, _eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0)
        LOG.info("packet in %s %s %s %s",
                 dpid, haddr_to_str(src), haddr_to_str(dst), msg.in_port)

        if _eth_type == ether.ETH_TYPE_ARP:
            #if dst in self.port_to_switch_mac[dpid]:
            arp_pkt = self.find_packet(msg,'arp')
            if arp_pkt != None:
                dst_ip = arp_pkt.dst_ip
                src_ip = arp_pkt.src_ip
                
                self.port_to_ip.setdefault(dpid,{})
                self.port_to_ip[dpid][in_port] = (src_ip & 0Xffffff00) + 0xfe

                if dst_ip == self.port_to_ip[dpid][in_port]:
                    src_mac = self.port_to_switch_mac[dpid][in_port]
                
                    e = ethernet.ethernet(src,self.port_to_switch_mac[dpid][in_port],ether.ETH_TYPE_ARP)
                    if arp_pkt.opcode == arp.ARP_REQUEST:
                        opcode = arp.ARP_REPLY 
                    #else:
                        #opcode = arp.ARP_REV_REPLY
                    a = arp.arp(hwtype = 1,proto = 0x0800, hlen = 6, plen = 4, opcode = opcode,
                        src_mac = src_mac,src_ip = arp_pkt.dst_ip,
                        dst_mac = arp_pkt.src_mac, dst_ip = arp_pkt.src_ip)
                    p = Packet()
                    p.add_protocol(e)
                    p.add_protocol(a) 
                    p.serialize()             
                                    
                    datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,actions=[datapath.ofproto_parser.OFPActionOutput(in_port)],data=p.data)

                    print "arp request packet's dst_mac is ",haddr_to_str(self.port_to_switch_mac[dpid][in_port])
                    


        
        if _eth_type == ether.ETH_TYPE_IP:
            ip_pkt = self.find_packet(msg,'ipv4')
            #to judge if the ip packet contains icmp protocol
            #print 'lee 0'
            if ip_pkt.proto == 1:
                icmp_pkt = self.find_packet(msg,'icmp')
                if icmp_pkt.type == icmp.ICMP_ECHO_REQUEST:
                    ip_src = ip_pkt.src
                    ip_dst = ip_pkt.dst

                    echo_id = icmp_pkt.data.id
                    echo_seq = icmp_pkt.data.seq
                    echo_data = bytearray(icmp_pkt.data.data)

                    icmp_data = icmp.echo(id_=echo_id,seq=echo_seq,data=echo_data)
                    
                    self.port_to_ip.setdefault(dpid, {})
                    #mask is 24 bit
                    self.port_to_ip[dpid][in_port] = (ip_src & 0Xffffff00) + 0xfe
                    #print 'lee 1'
                    if self.port_to_ip[dpid][in_port] == ip_dst:
                        #send a echo reply packet  
                        ether_dst = src
                        ether_src = self.port_to_switch_mac[dpid][in_port]
                        e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IP)
                        #csum calculation should be paied attention
                        #ic = icmp.icmp(type_= 0,code=0,csum=0,data=icmp_pkt.data)
                        i = ipv4.ipv4(version=4,header_length=5,tos=0,total_length=0,
                            identification=0,flags=0x000,offset=0,ttl=64,proto=1,csum=0,src=ip_dst,
                            dst=ip_src,option=None)

                        ic = icmp.icmp(type_= 0,code=0,csum=0,data=icmp_data)
                        p = Packet()
                        p.add_protocol(e)
                        p.add_protocol(i)
                        p.add_protocol(ic) 
                        p.serialize()                       
                        datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,actions=[datapath.ofproto_parser.OFPActionOutput(in_port)],data=p.data)
                        print 'send a ping replay'                        
                    else:
                        pass
        
        if _eth_type == ether.ETH_TYPE_IPV6:
            ipv6_pkt = self.find_packet(msg,'ipv6')
            #don't care about ipv6's extention header
            icmpv6_pkt = self.find_packet(msg,'icmpv6')
            if icmpv6_pkt != None:
                if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:

                    self.port_to_ipv6.setdefault(dpid,{})
                    #self.port_to_ipv6[dpid][in_port]=hexlify(((ipv6_pkt.src & (1<<128))-(1<<64)) + (1<<64) - 2)
                    self.port_to_ipv6[dpid][in_port]=struct.pack('!4I',0x100000,0x0,0xffffffff,0xfffffffd)
                    
                    if icmpv6_pkt.data.dst == self.port_to_ipv6[dpid][in_port]:
                           
                        #send a ND_NEIGHBOR_REPLY packet
                        ether_dst = src
                        ether_src = self.port_to_switch_mac[dpid][in_port]
                        e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IPV6)
                        
                        ic6_data_data = icmpv6.nd_option_la(hw_src=self.port_to_switch_mac[dpid][in_port],data=None)
                        #res = 3 or 7
                        ic6_data = icmpv6.nd_neighbor(res=3,dst=icmpv6_pkt.data.dst,type_=icmpv6.nd_neighbor.ND_OPTION_TLA,length=1,data=ic6_data_data)
                        ic6 = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT,code=0,csum=0,data=ic6_data)  
                        #payload_length
                        i6 = ipv6.ipv6(version= 6,traffic_class=0,flow_label=0,payload_length=32,nxt=58,hop_limit=255,
                            src=icmpv6_pkt.data.dst,dst=ipv6_pkt.src) 
                        p = Packet()
                        p.add_protocol(e)
                        p.add_protocol(i6)
                        p.add_protocol(ic6) 
                        p.serialize() 
                        datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,actions=[datapath.ofproto_parser.OFPActionOutput(in_port)],data=p.data)
                        print 'send a NA packet'
                        
                
                if icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
                    if self.port_to_ipv6[dpid].has_key(in_port):
                       
                    #print hexlify(self.port_to_ipv6[dpid][in_port])
                    #print 'ipv6_pkt.dst is',hexlify(ipv6_pkt.dst)
                    #print 'ipv6_pkt.dst is',hexlify(ipv6_pkt.dst)                  
                        if ipv6_pkt.dst == self.port_to_ipv6[dpid][in_port]:
                            ether_dst = src
                            ether_src = self.port_to_switch_mac[dpid][in_port]
                            e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IPV6)
                            ic6_data = icmpv6_pkt.data
                            ic6 = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY,code=0,csum=0,data=ic6_data)
                            i6 = ipv6.ipv6(version= 6,traffic_class=0,flow_label=0,payload_length=64,nxt=58,hop_limit=64,
                                src=ipv6_pkt.dst,dst=ipv6_pkt.src)
                            p = Packet()
                            p.add_protocol(e)
                            p.add_protocol(i6)
                            p.add_protocol(ic6) 
                            p.serialize() 
                            datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,actions=[datapath.ofproto_parser.OFPActionOutput(in_port)],data=p.data)
                            print 'send a ping6 reply packet'


                                        
                    

        # learn a mac address to avoid FLOOD next time.
        self.mac_to_port[dpid][src] = msg.in_port

        if dst in self.mac_to_port[dpid]:
            out_port = self.mac_to_port[dpid][dst]
        else:
            out_port = ofproto.OFPP_FLOOD

        actions = [datapath.ofproto_parser.OFPActionOutput(out_port)]
        if out_port != ofproto.OFPP_FLOOD:
            if _eth_type == ether.ETH_TYPE_IP:
                self.add_flow(datapath, msg.in_port, dst, actions)        
            #add a ipv6 flow table pay attention ipv6_flow entry only be added once when ipv4 flow entry is added       
            elif _eth_type == ether.ETH_TYPE_IPV6:

                '''
                # judge if src and dst addr is special 
                # eg: src [0,0,0,0] dst begin with 0xff01 or 0x ff02 
                if ipv6_src == [0,0,0,0] or ipv6_dst[0]&0xff010000 == 0xff010000 or ipv6_dst[0]&0xff020000 == 0xff020000:
                    print 'ipv6 reserved address\n' 
                #elif ipv6_dst[0]&0xfe800000 == 0xfe800000:
                #    print 'ipv6 dst address is Link-Local address'
                else:
                '''     
                
                ipv6_pkt = self.find_packet(msg,'ipv6')
                #ipv6_src=struct.pack('!4I',self._binary_to_ipv6_format(ipv6_packet.src))
                #ipv6_dst=struct.pack('!4I',self._binary_to_ipv6_format(ipv6_packet.dst))
                ipv6_src = convert.bin_to_ipv6_arg_list(ipv6_pkt.src)
                ipv6_dst = convert.bin_to_ipv6_arg_list(ipv6_pkt.dst)
                """
                ipv6_src = struct.pack('!4I',int(hexlify(ipv6_pkt.src)[0:8],16),int(hexlify(ipv6_pkt.src)[8:16],16),int(hexlify(ipv6_pkt.src)[16:24],16),int(hexlify(ipv6_pkt.src)[24:32],16))
                ipv6_dst = struct.pack('!4I',int(hexlify(ipv6_pkt.dst)[0:8],16),int(hexlify(ipv6_pkt.dst)[8:16],16),int(hexlify(ipv6_pkt.dst)[16:24],16),int(hexlify(ipv6_pkt.dst)[24:32],16))
                """   
                rule={'ipv6_src':ipv6_src,'ipv6_dst':ipv6_dst}
                self.nx_ipv6_add_flow(datapath,rule,actions)
                print 'add a ipv6 flow entry'  
            else:
                pass
          
        out = datapath.ofproto_parser.OFPPacketOut(
            datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
            actions=actions)
        datapath.send_msg(out)                 
    def _packet_in_handler(self, ev):
        # If you hit this you might want to increase 
        # the "miss_send_length" of your switch
        if ev.msg.msg_len < ev.msg.total_len:
            self.logger.debug("packet truncated: only %s of %s bytes",ev.msg.msg_len, ev.msg.total_len)

        #Extracting Message informations
        #Topology stuff
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        #Protocol stuff
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]

        dst = eth.dst
        src = eth.src

        i = pkt.get_protocol(ipv6)
        #if it's not related to IPV6, not considered
        if i is None:
            #Here you can get lldp packets
           return 0
        print("------------IPV6 PACKET------------")
        
        if(self.RoutingDone==False):
            #If it's the first ipv6 packet received routing must be done before
            self.collectRoutingInfo()

        pkt_type =0         
        dpid = datapath.id
        print 'DPID::{}'.format(dpid)
        
        #Examining protocols in the IP packet
        for p in pkt.protocols:
            #Handling icmpv6 packets
            if p.protocol_name == 'icmpv6':
                pkt_type=1
            if pkt_type == 1:
                print("-----------------ICMPv6-----------------")	
                icmp = pkt.get_protocols(icmpv6.icmpv6)[0]
                itype = 0
                found = 0
                prefix =''
                if icmp.type_== 133:
                    print 'Type : Router Solicitation'
                    itype = 1
                elif icmp.type_== 134:
                    print 'Type : Router Advertisement'
                    itype = 2
                elif icmp.type_== 128:
                    print 'Type : Echo Request'
                    itype = 4
                elif icmp.type_== 129:
                    print 'Type : Echo Reply'
                    itype = 5
                elif icmp.type_ ==136:
                    print 'Type : Neighbour Advertisement'
                    itype=3
                elif icmp.type_ ==135:
                    print'Type : Neighbour Solicitation'
                    itype=6
                else:
                    print 'Type : other ICMPV6 message'
                    print (icmp.type_)

        
        #mac_to_port is not used 
        self.mac_to_port.setdefault(dpid, {})
        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
        print("Details : packet in ", dpid, src, dst, in_port)
        #once protocols are known, it's time to prepare answers
 
        #temporary solution : here no authentication protocol
        #every user are granted
        found=1
        
        #In case of Router Solicitation
        if((itype == 1)&(found == 1)):
            
            #checking if the incomming port is not a backbone port:
            validIntf=True;
            for link in self.linkList:
                if (link.src.dpid,link.src.port_no) == (dpid,in_port) or (link.dst.dpid,link.dst.port_no) == (dpid,in_port):
                    validIntf = False;
                    print('local host registration : non valid input interface (belongs to backbone)')
                    break
            
            if not validIntf :
                return 0;
            
            #computing the global ipv6 address the host will forge
            nbrZeros=3-len(str(dpid))
            newPrefix='2'+'0'*nbrZeros+str(dpid)
            newAddress = self.forgeHostGlobalIP(src,newPrefix)

            #registering or updating host in the current router
            hostDetails = (eth.src,in_port)
            self.coveredHosts[dpid][newAddress]=hostDetails
            
            print ('coveredHost updated : switch ', dpid)
            print self.coveredHosts

            #registering the interface in the bindingList
            #done if the interface is not discovered already (dynamic linking),             
            if (dpid,in_port) not in self.bindingList.keys():
                self.bindingList[dpid,in_port]='2'+'0'*nbrZeros+str(dpid)+'::'+str(in_port)
                print ('bindingList updated : switch ', dpid)
                print self.bindingList

            print ('local host registration : host : ', eth.src , ' registered under ',dpid,' coverage at interface number ',in_port, 'with ip@ :', newAddress )
            #Mobility Management Procedure is fired
            
            #Asking for the list of the prior network
            #And updating it with the current one
            #host ID based on MAC address
            #the currrent datapath is also provided
            priorNetworks = self.mobTracker.getTraceAndUpdate(src,datapath);
            print('~~~~~~~~~~NODE HAS REGISTERED~~~~~~~~~~')
            print('previous networks : ')
            print (priorNetworks)
            print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')

            #if the list is empty there is nothing more to do
            #if not tunnels must be set up:
            if priorNetworks is not None:
                #maintaining a list in order to know when to stop in the tunnel creation/updating
                #and in order not to create a tunnel that will be updated in the same procedure
                updatedTunnels=[]
                #creating tunnels with all the previous network and the current one
                for priorDp in priorNetworks[:-1]:
                    print('###########SETTING UP TUNNEL############')
                    #Getting new tunnel identifier, a tunnelID is build with
                    #the concatenation of the old router ID and the new router ID
                    tunID = int(str(priorDp.id)+str(datapath.id))
                    #when a already updated tunnel is met, it is skipped
                    if tunID in updatedTunnels:
                        continue;
                    #else it's registered to the list and the procedure is launched
                    updatedTunnels.append(tunID)

                    #fetching IP addr the host forged in the previous network
                    #in asking coveredHost dict with the provided MAC @
                    priorAddress = None 
                    for ipAddress in self.coveredHosts[priorDp.id].keys():
                        #comparing MAC addresses
                        if self.coveredHosts[priorDp.id][ipAddress][0]==src:
                            priorAddress=ipAddress
                            break
                    else:
                        #if the mac address is not associated to any ip address, exit
                        print('the host with mac @ : ',src,' has never visited ' , priorDp.id , ' here is its covered Hosts : ')
                        print( self.coveredHosts[priorDp.id])
                        return 0;

                    # nbrZeros=3-len(str(priorDp.id))
                    # priorPrefix='2'+'0'*nbrZeros+str(priorDp.id)
                    # #priorPrefix = str('200')+str(priorDp.id)
                    # priorAddress = self.forgeHostGlobalIP(src,priorPrefix)
                    
                    if priorDp.id != datapath.id:
                        #set up tunnel, host MAC @ is considered as identifier
                        self.setUpTunnel(priorAddress,priorDp,datapath,tunID)
                        print('tunnel set up from ', priorDp.id, ' to ', datapath.id)
                        #Each previously built address is included in a proactively pushed flow for
                        #forwarding on the input interface which is registered in table 3 of the new
                        #covering router. so that the NewInput flow forwards packets to this
                        #table to resolve the local output interface
                        #
                        #in_port is the interface to which packets comming from the tunnel have to be forwarded to
                        
                        #if the node change the interface it is linked to
                        #the switch, a new router solicitation is sent,
                        #all the tunnel are then updated and so is table 2
 
                        output_intf = in_port
                        match2 = parser.OFPMatch( eth_type=0x86dd, ip_proto=58, ipv6_dst=(priorAddress,'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))
                        #set up mac addresses
                        new_mac_src = self.generateMAC(dpid,output_intf)
                        new_mac_dst = eth.src
                        action2 = [parser.OFPActionDecNwTtl(), parser.OFPActionSetField(eth_src=new_mac_src),
                                   parser.OFPActionSetField(eth_dst=new_mac_dst),parser.OFPActionOutput(output_intf) ]
            
                        #remote address routing related flow then pushed to table 2
                        self.add_flow(datapath, 1, match2, action2,tblId=2)
                        print('Remote Routing Flow : prior address ', priorAddress, ' -> interface : ',output_intf,' written in switch ', datapath.id) 

                    else:
                        #if the network is back in a previously visited network
                        #redirect the tunneled flow on the local interface
                        print('Mobile node ',src,' is back to network ', dpid)
                        matchBack = datapath.ofproto_parser.OFPMatch( eth_type=0x86dd, ip_proto=58,vlan_vid=0x000, ipv6_dst=(priorAddress,'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))
                        output_port = in_port
                        new_mac_src = self.generateMAC(priorDp.id,output_port)
                        new_mac_dst = src
                        actionsBack = [datapath.ofproto_parser.OFPActionDecNwTtl(), datapath.ofproto_parser.OFPActionSetField(eth_src=new_mac_src),
                            datapath.ofproto_parser.OFPActionSetField(eth_dst=new_mac_dst)]
                        instsBack = [datapath.ofproto_parser.OFPInstructionActions(datapath.ofproto.OFPIT_APPLY_ACTIONS,actionsBack)]
                        #Forward to normal routing table (table 1)
                        instsBack.append(datapath.ofproto_parser.OFPInstructionGotoTable(1))
                        modBack = datapath.ofproto_parser.OFPFlowMod(datapath=datapath, priority=65535, match=matchBack,instructions=instsBack)
                        datapath.send_msg(modBack)
        



                        print('Tunnel flow pushed to switch ' ,datapath.id ,' to make packets going to ', priorAddress, ' going to local network again')


                                      
            #once flows are set up, router advertisement has to be sent
            #create RA including the allocated prefix (should consider multiple prefixes later) 
            #direct reply on the incomming switch port
            out_port = in_port 
            pkt_generated = packet.Packet()
            e= ethernet.ethernet(dst=str(eth.src),src=self.generateMAC(dpid,in_port), ethertype=ether.ETH_TYPE_IPV6)
    
            #AS IT IS A REPLY TO ROUTER SOLLICITATION : SOURCE @ MUST BE LOCAL SCOPE!!
            srcIP = self.generateLL(dpid,in_port)
            ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=srcIP, dst=str(i.src))
            #setting up prefix : the dependant Local Network prefix is returned
            #nbrZeros=3-len(str(dpid))
            #prefix='2'+'0'*nbrZeros+str(dpid)+'::1'
            prefix=self.bindingList[dpid,in_port]
            icmp_v6 = icmpv6.icmpv6(type_=icmpv6.ND_ROUTER_ADVERT, data=icmpv6.nd_router_advert(ch_l=64, rou_l=4, options=[icmpv6.nd_option_pi(length=4, pl=64, res1=7, val_l=86400, pre_l=14400, prefix=prefix)]))
            pkt_generated.add_protocol(e)
            pkt_generated.add_protocol(ip)
            pkt_generated.add_protocol(icmp_v6)
            pkt_generated.serialize()
            actions = [parser.OFPActionOutput(out_port)]	
            out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
            datapath.send_msg(out_ra)
            print('>>>>>>>>>> ROUTER ADVERTISEMENT SENT <<<<<<<<<<')
            return
        
        #handling neighbour solicitation
        elif itype==6:
            neighSol = pkt.get_protocols(icmpv6.icmpv6)[0]
            print (neighSol)
            opt = neighSol.data.option
            trg = neighSol.data.dst
            
            if opt is not None :
            #if opt is not None, the NS is for getting the MAC @ of a given IP @
                if isinstance(opt,ryu.lib.packet.icmpv6.nd_option_sla):
                #link layer address request

                    #check if the solicited @ is the one of the router 
                    #fetching all the local addresses and the associated port of the current switch
                    trgPort = None
                    localAddressesIntfList = [ [self.bindingList[localPort],localPort[1]] for localPort in self.bindingList.keys() if localPort[0]==dpid ]

                    addrList = [addr[0] for addr in localAddressesIntfList ]
                    if str(trg) in addrList:
                        print('resolving switch mac address')
                        index = addrList.index(str(trg))
                        trgPort = localAddressesIntfList[index][1]

                    #if no address has been found, switch checks if the asking address
                    #is one of another local host since there are now several local 
                    #interfaces under which hosts have the same prefix
                    if trgPort is None:
                        #checking if mac @ of another local host is asked
                        if str(trg) in self.coveredHosts[dpid].keys():
                            print('resolving other local host address')
                            #returning incomming port, so that the asking node
                            #will use the mac @ of the switch's interface it's linked to
                            trgPort = in_port

                    #if the request concerns the router, prepare answer:
                    if trgPort is not None :
                        #get hw@
                        hw_addr = opt.hw_src
                        #reply with a neighbor adv
                        neigh_adv = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT, data=icmpv6.nd_neighbor(res=7, dst=str(trg), option=icmpv6.nd_option_tla(hw_src=self.generateMAC(dpid,trgPort))))
                        e= ethernet.ethernet(dst=str(hw_addr),src=self.generateMAC(dpid,in_port), ethertype=ether.ETH_TYPE_IPV6)
                        #here reply with global scope @
                        srcIP = self.bindingList[dpid,in_port]
                        ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=srcIP, dst=str(i.src))
                        
                        #direct reply on the incomming switch port
                        out_port = in_port 
                        pkt_generated = packet.Packet()

                    
                        pkt_generated.add_protocol(e)
                        pkt_generated.add_protocol(ip)
                        pkt_generated.add_protocol(neigh_adv)
                        pkt_generated.serialize()                        

                        #ACTION : the NA must be forwarded on the incomming switch port
                        
                        actions = [parser.OFPActionOutput(out_port)]	
                        out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
                        datapath.send_msg(out_ra)
                        print('..........neighbor advertisement sent..........')
                    else:
                        print(trg, ' address neither belongs to switch or local host')
            else:
                print('neighbor solicitation conflict resolution')
                #nothing is done here all the registration porcess is now done a the reception
                #or the router solicitation

        #handling ping requests and reply
        elif itype == 4 or itype == 5:
            #looking at destination address, finding out which is the next hope, changing MAC @ 
            ping_src = i.src
            ping_dst = i.dst
            echo = pkt.get_protocols(icmpv6.icmpv6)[0];
            print(echo)
            
            #when ip dst @ is known : 3 cases:

            #destination is behind another router
            #destination is behind the current router
            #destination is the current router 
            
            #fetching all the local addresses of the current switch
            localAddressesList = [ self.bindingList[localPort] for localPort in self.bindingList.keys() if localPort[0]==dpid ]

            if ping_dst in localAddressesList :
                print('ping addressed to the router')
                #the ping is addressed to the switch:
                #if it's a request : reply
                if itype == 4:
                    #copy request data into the reply
                    reqData = echo.data
                    pingReply = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY, data=reqData)
                    #direct reply on the incomming switch port
                    out_port = in_port 

                    e= ethernet.ethernet(dst=src,src=dst, ethertype=ether.ETH_TYPE_IPV6)
                    #here reply with global scope @
                    ip = ipv6(nxt=inet.IPPROTO_ICMPV6, src=str(ping_dst), dst=str(ping_src))
                    pkt_generated = packet.Packet()

                    pkt_generated.add_protocol(e)
                    pkt_generated.add_protocol(ip)
                    pkt_generated.add_protocol(pingReply)
                    print('.........................')
                    print(pkt_generated)
                    pkt_generated.serialize()
                    #ACTION : the NA must be forwarded on the incomming switch port
                    actions = [parser.OFPActionOutput(out_port)]
                    
                    out_ra = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=0, actions=actions, data=pkt_generated.data)
                    datapath.send_msg(out_ra)
                    print('..........Ping Reply sent..........')
                    
            else:
                print('ping another host or switch received by ', dpid, 'going to', ping_dst)

                #first step : finding out the destination switch
                #now only host pinging is considered (no ping to backbone intf of remote switch)
                extractedDomain = re.match(r"20*(?P<trgDpid>[1-9]{1,3})",ping_dst[0:4])
                #getting the dpid covering the destination host
                extractedDpid = int(extractedDomain.group('trgDpid'))
                
                if extractedDpid is None :
                    #if extractedDpid is None it mean that dest address begins with 2000:
                    #this is a backbone interface ip address
                    #
                    #extracting the switch to which this interface belongs
                    extractedDest = re.match(r".+:{1,2}(?P<trgDpid>[0-9]{1,4})$",ping_dst)
                    extractedDpid = int(extractedDest.group('trgDpid'))

                #checking validity of the obtained dpid
                if extractedDpid in [s.dp.id for s in self.switchList]:
                    print ('ping going to ', ping_dst , ' must be routed to router ', str(extractedDpid) ,' as destination domain is ', ping_dst[0:4])
                #handle the case where no sub domain is found
                else:
                    print ('no subdomain found deleting packet')
                    #throw exception
                    return 0
                destDpid = extractedDpid
                #1st case destination covering switch is the current one
                if destDpid == dpid:
                    #checking if the ping destination is linked to one of the local interfaces
                    print('ping toward local network, resolving local interface')
                    if ping_dst not in self.coveredHosts[destDpid].keys():
                        print('destination: ', ping_dst ,' host is not linked to the domain switch, deleting packet')
                        return 0
                    #if destination host is linked to the switch, resolving the interface
                    outputIntf = self.coveredHosts[destDpid][ping_dst][1]
                    #setting new addresses MAC:
                    new_mac_src = self.generateMAC(destDpid,outputIntf)
                    new_mac_dst = self.coveredHosts[destDpid][ping_dst][0]
                    print('ping local host ', ping_dst , ' through interface ', outputIntf)

                #2nd case destination covering switch is not the current one
                else:#PING GOING OUTSIDE LOCAL NETWORK
                    #finding nexthop 
                    nextHopID = self.next_hop(dpid,destDpid)
                    #finding output interface
                    outputIntf = self.routing(dpid,nextHopID)
                    new_mac_src = self.generateMAC(dpid,outputIntf)
                    new_mac_dst = self.generateMAC(nextHopID,self.routing(nextHopID,dpid))
                    print ('ping toward neighbor ', outputIntf)
                        
                action = [parser.OFPActionDecNwTtl(), parser.OFPActionSetField(eth_src=new_mac_src),
                          parser.OFPActionSetField(eth_dst=new_mac_dst),parser.OFPActionOutput(outputIntf) ]
            
                match = parser.OFPMatch( eth_type=0x86dd, ip_proto=58, ipv6_dst=(ping_dst,'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'))
                print('ready to push flow to ',datapath)
                #routing related flow then pushed to table 1
                self.add_flow(datapath, 1, match, action,tblId=1)
                print('flow pushed')        
                
                

        else:
            print ('')
            print("========================================")            
Exemple #36
0
 def test_init(self):
     nd = icmpv6.nd_neighbor(self.res, self.dst)
     eq_(nd.res, self.res)
     eq_(nd.dst, self.dst)
     eq_(nd.option, None)
    def _handle_icmpv6(self, msg, pkt, icmpv6_pkt):
        LOG.debug('Handling ICMPv6 packet %s', icmpv6_pkt)

        ipv6_pkt = self.find_packet(pkt, 'ipv6')
        dst_addr = netaddr.IPAddress(ipv6_pkt.dst)
        if dst_addr == netaddr.IPAddress(util.bgper_config['local_ipv6']):
            self.write_to_tap(pkt.data, modifyMacAddress=True)
            # DON'T return here

        switch = self.dpid_to_switch[msg.datapath.id]
        in_port_no = msg.in_port

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            gateway = switch.ports[in_port_no].gateway
            pop_list = []
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            if gateway and gateway.gw_ipv6 == netaddr.IPAddress(ipv6_pkt.dst):
                self._remember_mac_addr(switch, pkt, 6)
                for i in xrange(len(switch.msg_buffer)):
                    msg, pkt, outport_no, _4or6 = switch.msg_buffer[i]
                    if self.last_switch_out(msg, pkt, outport_no, _4or6):
                        pop_list.append(i)

                pop_list.sort(reverse=True)
                for i in pop_list:
                    switch.msg_buffer.pop(i)

                return True
            return False

        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            port = switch.ports[in_port_no]
            LOG.debug('ND_NEIGHBOR_SOLICIT, dest %s', icmpv6_pkt.data.dst)
            if port.gateway and \
               netaddr.IPAddress(icmpv6_pkt.data.dst) != port.gateway.gw_ipv6:
                return False
            #send a ND_NEIGHBOR_REPLY packet
            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = str(port.hw_addr)
            e = ethernet.ethernet(ether_dst, ether_src, ether.ETH_TYPE_IPV6)
            ic6_data_data = icmpv6.nd_option_tla(hw_src=ether_src, data=None)
            # res: R, S, O flags for Neighbor advertisement
            # R: Router flag. Set if the sender of the advertisement is a router
            # S: Solicited flag. Set if the advertisement is in response to a
            #    solicitation
            # O: Override flag. When set, the receiving node must update its cache
            # here we must set R, S; O is optional but we decide to set
            # so res = 7
            ic6_data = icmpv6.nd_neighbor(res=7,
                                          dst=icmpv6_pkt.data.dst,
                                          option=ic6_data_data)
            ic6 = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT,
                                code=0,
                                csum=0,
                                data=ic6_data)
            #payload_length
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            i6 = ipv6.ipv6(version=6,
                           traffic_class=0,
                           flow_label=0,
                           payload_length=32,
                           nxt=58,
                           hop_limit=255,
                           src=icmpv6_pkt.data.dst,
                           dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(
                in_port=ofproto_v1_0.OFPP_NONE,
                actions=[datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                data=p.data)
            LOG.debug('NA packet sent %s -> %s', icmpv6_pkt.data.dst,
                      ipv6_pkt.src)
            return True
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            ipv6_pkt = self.find_packet(pkt, 'ipv6')

            need_reply = False
            for _k, p in switch.ports.iteritems():
                if p.gateway and \
                        p.gateway.gw_ipv6 == netaddr.IPAddress(ipv6_pkt.dst):
                    need_reply = True
                    break
            if not need_reply:
                return False

            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = str(switch.ports[in_port_no].hw_addr)
            e = ethernet.ethernet(ether_dst, ether_src, ether.ETH_TYPE_IPV6)
            ic6_data = icmpv6_pkt.data
            ic6 = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY,
                                code=0,
                                csum=0,
                                data=ic6_data)
            i6 = ipv6.ipv6(version=6,
                           traffic_class=0,
                           flow_label=0,
                           payload_length=64,
                           nxt=58,
                           hop_limit=64,
                           src=ipv6_pkt.dst,
                           dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(
                in_port=ofproto_v1_0.OFPP_NONE,
                actions=[datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                data=p.data)
            LOG.debug('Ping6 replied %s -> %s', ipv6_pkt.dst, ipv6_pkt.src)
            return True

        return False
Exemple #38
0
    def _packet_in_handler(self, ev):
        '''
            In packet_in handler, we need to learn access_table by ARP.
            Therefore, the first packet from UNKOWN host MUST be ARP.
        '''
        msg = ev.msg
        datapath = msg.datapath
        in_port = msg.match['in_port']
        pkt = packet.Packet(msg.data)
        arp_pkt = pkt.get_protocol(arp.arp)
        ipv4_pkt = pkt.get_protocol(ipv4.ipv4)
        ipv6_pkt = pkt.get_protocol(ipv6.ipv6)
        icmpv6_pkt = pkt.get_protocol(icmpv6.icmpv6)
        parser = datapath.ofproto_parser
        ofproto = datapath.ofproto
        no_thing = 0

        # print("!!!!!!!!!!!!!!!!!!!!!!!!")
        # print(self.port_mac_dic)
        # print(self.awareness.ipv6_access_table)

        if isinstance(arp_pkt, arp.arp):
            self.logger.debug("ARP processing")
            if 6 <= in_port <= 11:
                eth_src = '02'
                for i in range(0, 5):
                    r = random.randint(0, 255)
                    s = ':' + ('00' + hex(r)[2:])[-2:]
                    eth_src += s
                match = parser.OFPMatch(in_port=in_port, eth_type=0x806, arp_op=1)
                actions =  [parser.OFPActionSetField(eth_src=eth_src),
                            parser.OFPActionSetField(eth_dst=pkt[0].src),
                            parser.OFPActionSetField(arp_op=2),
                            parser.OFPActionSetField(arp_spa=pkt[1].dst_ip),
                            parser.OFPActionSetField(arp_tpa=pkt[1].src_ip),
                            parser.OFPActionSetField(arp_sha=eth_src),
                            parser.OFPActionSetField(arp_tha=pkt[1].src_mac),
                            parser.OFPActionOutput(port=ofproto.OFPP_IN_PORT)]
                self.add_flow(datapath, 1, match, actions,
                      idle_timeout=600, hard_timeout=1200)
            else:    
                self.arp_forwarding(msg, arp_pkt.src_ip, arp_pkt.dst_ip)
       
        if isinstance(ipv4_pkt, ipv4.ipv4):
            self.logger.debug("IPV4 processing")
            if len(pkt.get_protocols(ethernet.ethernet)):
                eth_type = pkt.get_protocols(ethernet.ethernet)[0].ethertype
                self.shortest_forwarding(msg, eth_type, ipv4_pkt.src, ipv4_pkt.dst)

        if isinstance(ipv6_pkt, ipv6.ipv6):
            self.logger.debug("IPV6 processing")
            if len(pkt.get_protocols(ethernet.ethernet)):
                if len(pkt) == 3 and 133 <= pkt[2].type_ <= 137:
                    self.logger.debug("ICMPv6 processing")
                    if pkt[2].type_ == 133:
                        ra_pkt = self.generate_ra_pkt(datapath, in_port)
                        ra_pkt.serialize()
                        data = ra_pkt.data
                        actions = [parser.OFPActionOutput(port=in_port)]
                        out = parser.OFPPacketOut(datapath=datapath,
                                                    buffer_id=ofproto.OFP_NO_BUFFER,
                                                    in_port=ofproto.OFPP_CONTROLLER,
                                                    actions=actions,
                                                    data=data)
                        datapath.send_msg(out)
                    
                    #if ip_address(pkt[2].data.dst) in ip_network("64:ff9b::/96"):
                    if pkt[2].type_ == 135:
                        eth_src = self.port_mac_dic[datapath.id][in_port]
                        #eth_src = "50:af:73:24:48:b1" 
                        nd_data_recv = pkt[2].data
                        assert isinstance(nd_data_recv, icmpv6.nd_neighbor)
                        target_addr = nd_data_recv.dst
                        nd_option_tla = icmpv6.nd_option_tla(hw_src=eth_src)
                        na_data = icmpv6.nd_neighbor(res=6, dst=target_addr, option=nd_option_tla)
                        na_pkt = packet.Packet()
                        na_pkt.add_protocol(ethernet.ethernet(ethertype=0x86DD, dst=pkt[0].src, src=eth_src))
                        na_pkt.add_protocol(ipv6.ipv6(dst=pkt[1].src, src=setting.Port_link_dic[datapath.id][in_port], nxt=58))
                        na_pkt.add_protocol(icmpv6.icmpv6(type_=136, code=0, data=na_data))
                        na_pkt.serialize()
                        data = na_pkt.data
                        actions = [parser.OFPActionOutput(port=in_port)]
                        out = parser.OFPPacketOut(datapath=datapath,
                                                    buffer_id=ofproto.OFP_NO_BUFFER,
                                                    in_port=ofproto.OFPP_CONTROLLER,
                                                    actions=actions,
                                                    data=data)
                        datapath.send_msg(out)    
                        #self.icmpv6nd_forwarding(msg, pkt[1].src, pkt[1].dst)
                    
                else:
                    if ip_address(ipv6_pkt.dst) != ip_address('2001:da8:202:10::36'):
                        eth_type = pkt.get_protocols(ethernet.ethernet)[0].ethertype
                        self.shortest_forwarding(msg, eth_type, ipv6_pkt.src, ipv6_pkt.dst)
    def _handle_icmpv6(self, msg, pkt, icmpv6_pkt):
        LOG.debug('Handling ICMPv6 packet %s', icmpv6_pkt)

        ipv6_pkt = self.find_packet(pkt, 'ipv6')
        dst_addr = netaddr.IPAddress(ipv6_pkt.dst)
        if dst_addr == netaddr.IPAddress(util.bgper_config['local_ipv6']):
            self.write_to_tap(pkt.data, modifyMacAddress=True)
            # DON'T return here

        switch = self.dpid_to_switch[msg.datapath.id]
        in_port_no = msg.in_port

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            gateway = switch.ports[in_port_no].gateway
            pop_list = []
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            if gateway and gateway.gw_ipv6 == netaddr.IPAddress(ipv6_pkt.dst):
                self._remember_mac_addr(switch, pkt, 6)
                for i in xrange(len(switch.msg_buffer)):
                    msg, pkt, outport_no, _4or6 = switch.msg_buffer[i]
                    if self.last_switch_out(msg, pkt, outport_no, _4or6):
                        pop_list.append(i)

                pop_list.sort(reverse = True)
                for i in pop_list:
                    switch.msg_buffer.pop(i)

                return True
            return False

        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            port = switch.ports[in_port_no]
            LOG.debug('ND_NEIGHBOR_SOLICIT, dest %s',
                      icmpv6_pkt.data.dst)
            if port.gateway and \
               netaddr.IPAddress(icmpv6_pkt.data.dst) != port.gateway.gw_ipv6:
                return False
            #send a ND_NEIGHBOR_REPLY packet
            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = str(port.hw_addr)
            e = ethernet.ethernet(ether_dst, ether_src, ether.ETH_TYPE_IPV6)
            ic6_data_data = icmpv6.nd_option_tla(hw_src=ether_src, data=None)
            # res: R, S, O flags for Neighbor advertisement
            # R: Router flag. Set if the sender of the advertisement is a router
            # S: Solicited flag. Set if the advertisement is in response to a
            #    solicitation
            # O: Override flag. When set, the receiving node must update its cache
            # here we must set R, S; O is optional but we decide to set
            # so res = 7
            ic6_data = icmpv6.nd_neighbor(res=7, dst=icmpv6_pkt.data.dst,
                                          option=ic6_data_data)
            ic6 = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT, code=0,
                                csum=0, data=ic6_data)
            #payload_length
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            i6 = ipv6.ipv6(version= 6, traffic_class=0, flow_label=0,
                           payload_length=32, nxt=58, hop_limit=255,
                           src=icmpv6_pkt.data.dst, dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,
                    actions=
                        [datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                    data=p.data)
            LOG.debug('NA packet sent %s -> %s', icmpv6_pkt.data.dst,
                      ipv6_pkt.src)
            return True
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            ipv6_pkt = self.find_packet(pkt, 'ipv6')

            need_reply = False
            for _k, p in switch.ports.iteritems():
                if p.gateway and \
                        p.gateway.gw_ipv6 == netaddr.IPAddress(ipv6_pkt.dst):
                    need_reply = True
                    break
            if not need_reply:
                return False

            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = str(switch.ports[in_port_no].hw_addr)
            e = ethernet.ethernet(ether_dst,ether_src,ether.ETH_TYPE_IPV6)
            ic6_data = icmpv6_pkt.data
            ic6 = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY, code=0,
                                csum=0, data=ic6_data)
            i6 = ipv6.ipv6(version=6, traffic_class=0, flow_label=0,
                           payload_length=64, nxt=58, hop_limit=64,
                           src=ipv6_pkt.dst, dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(in_port=ofproto_v1_0.OFPP_NONE,
                    actions=
                        [datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                    data=p.data)
            LOG.debug('Ping6 replied %s -> %s', ipv6_pkt.dst, ipv6_pkt.src)
            return True

        return False
 def test_init(self):
     nd = icmpv6.nd_neighbor(self.res, self.dst)
     eq_(nd.res, self.res)
     eq_(nd.dst, self.dst)
     eq_(nd.option, None)
Exemple #41
0
    def _handle_icmpv6(self, msg, pkt, icmpv6_pkt):
        #print 'icmpv6', icmpv6_pkt

        switch = self.dpid_to_switch[msg.datapath.id]
        in_port_no = msg.in_port

        if icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_ADVERT:
            gateway = switch.ports[in_port_no].gateway
            pop_list = []
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            if gateway and gateway.gw_ipv6 == ipv6_pkt.dst:
                self._remember_mac_addr(switch, pkt, 6)
                for i in xrange(len(switch.msg_buffer)):
                    msg, pkt, outport_no, _4or6 = switch.msg_buffer[i]
                    if self.last_switch_out(msg, pkt, outport_no, _4or6):
                        pop_list.append(i)

                pop_list.sort(reverse=True)
                for i in pop_list:
                    switch.msg_buffer.pop(i)

                return True
            return False

        elif icmpv6_pkt.type_ == icmpv6.ND_NEIGHBOR_SOLICIT:
            port = switch.ports[in_port_no]
            if port.gateway and icmpv6_pkt.data.dst != port.gateway.gw_ipv6:
                print convert.bin_to_ipv6(icmpv6_pkt.data.dst)
                print convert.bin_to_ipv6(port.gateway.gw_ipv6)
                return False
            #send a ND_NEIGHBOR_REPLY packet
            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = port.hw_addr
            e = ethernet.ethernet(ether_dst, ether_src, ether.ETH_TYPE_IPV6)
            ic6_data_data = icmpv6.nd_option_la(hw_src=ether_src, data=None)
            #res = 3 or 7
            ic6_data = icmpv6.nd_neighbor(
                res=3,
                dst=icmpv6_pkt.data.dst,
                type_=icmpv6.nd_neighbor.ND_OPTION_TLA,
                length=1,
                data=ic6_data_data)
            ic6 = icmpv6.icmpv6(type_=icmpv6.ND_NEIGHBOR_ADVERT,
                                code=0,
                                csum=0,
                                data=ic6_data)
            #payload_length
            ipv6_pkt = self.find_packet(pkt, 'ipv6')
            i6 = ipv6.ipv6(version=6,
                           traffic_class=0,
                           flow_label=0,
                           payload_length=32,
                           nxt=58,
                           hop_limit=255,
                           src=icmpv6_pkt.data.dst,
                           dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(
                in_port=ofproto_v1_0.OFPP_NONE,
                actions=[datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                data=p.data)
            print 'send a NA packet'
            return True
        elif icmpv6_pkt.type_ == icmpv6.ICMPV6_ECHO_REQUEST:
            ipv6_pkt = self.find_packet(pkt, 'ipv6')

            need_reply = False
            for _k, p in switch.ports.iteritems():
                if p.gateway and p.gateway.gw_ipv6 == ipv6_pkt.dst:
                    need_reply = True
                    break
            if not need_reply:
                return False

            ether_layer = self.find_packet(pkt, 'ethernet')
            ether_dst = ether_layer.src
            ether_src = switch.ports[in_port_no].hw_addr
            e = ethernet.ethernet(ether_dst, ether_src, ether.ETH_TYPE_IPV6)
            ic6_data = icmpv6_pkt.data
            ic6 = icmpv6.icmpv6(type_=icmpv6.ICMPV6_ECHO_REPLY,
                                code=0,
                                csum=0,
                                data=ic6_data)
            i6 = ipv6.ipv6(version=6,
                           traffic_class=0,
                           flow_label=0,
                           payload_length=64,
                           nxt=58,
                           hop_limit=64,
                           src=ipv6_pkt.dst,
                           dst=ipv6_pkt.src)
            p = packet.Packet()
            p.add_protocol(e)
            p.add_protocol(i6)
            p.add_protocol(ic6)
            p.serialize()
            datapath = msg.datapath
            datapath.send_packet_out(
                in_port=ofproto_v1_0.OFPP_NONE,
                actions=[datapath.ofproto_parser.OFPActionOutput(in_port_no)],
                data=p.data)
            print 'send a ping6 reply packet'
            return True

        return False