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
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)
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)
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)
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
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)
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)
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
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
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)
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)
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)
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")
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 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)
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
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, '')
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, "")
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)
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)
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
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)
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("========================================")
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("========================================")
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("========================================")
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
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 _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