zoukankan      html  css  js  c++  java
  • ryu 环路

    [root@kunpeng82 demo1]# cat group.py
    from mininet.topo import Topo
    class MininetTopo(Topo):
        def __init__(self,**opts):
            Topo.__init__(self, **opts)
            host1 = self.addHost('h1')
            host2 = self.addHost('h2')
            host3 = self.addHost('h3')
            host4 = self.addHost('h4')
        
            self.switch = {}
            for s in range(1,5):
                self.switch[s-1] = self.addSwitch('s%s' %(s))
            self.addLink(self.switch[0], self.switch[1])
            self.addLink(self.switch[0], self.switch[2])
            self.addLink(self.switch[0], self.switch[3])
                #Adding host
            self.addLink(self.switch[0], host1)
            self.addLink(self.switch[1], host2)
            self.addLink(self.switch[2], host3)
            self.addLink(self.switch[3], host4)
            
    topos = {'group':(lambda:MininetTopo())}
    [root@kunpeng82 demo1]# 
    [root@kunpeng82 demo1]# mn --custom group.py  --topo group
    *** Creating network
    *** Adding controller
    *** Adding hosts:
    h1 h2 h3 h4 
    *** Adding switches:
    s1 s2 s3 s4 
    *** Adding links:
    (s1, h1) (s1, s2) (s1, s3) (s1, s4) (s2, h2) (s3, h3) (s4, h4) 
    *** Configuring hosts
    h1 h2 h3 h4 
    *** Starting controller
    c0 
    *** Starting 4 switches
    s1 s2 s3 s4 ...
    *** Starting CLI:
    mininet> h1 ping h2
    PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
    64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=134 ms
    64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.434 ms
    64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.053 ms
    ^C
    --- 10.0.0.2 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2026ms
    rtt min/avg/max/mdev = 0.053/45.037/134.626/63.349 ms
    mininet> h1 ping -c 3  h3
    PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
    64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=137 ms
    64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.371 ms
    64 bytes from 10.0.0.3: icmp_seq=3 ttl=64 time=0.032 ms
    
    --- 10.0.0.3 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2034ms
    rtt min/avg/max/mdev = 0.032/45.905/137.312/64.634 ms
    mininet> 
    Interrupt
    mininet> h1 ping -c 3  h4
    PING 10.0.0.4 (10.0.0.4) 56(84) bytes of data.
    64 bytes from 10.0.0.4: icmp_seq=1 ttl=64 time=133 ms
    64 bytes from 10.0.0.4: icmp_seq=2 ttl=64 time=0.458 ms
    64 bytes from 10.0.0.4: icmp_seq=3 ttl=64 time=0.040 ms
    
    --- 10.0.0.4 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2070ms
    rtt min/avg/max/mdev = 0.040/44.570/133.212/62.679 ms
    mininet> 
    [root@kunpeng82 demo1]# ovs-ofctl dump-flows s1
     cookie=0x0, duration=54.568s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=62:ca:42:08:6d:78,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2 actions=output:"s1-eth4"
     cookie=0x0, duration=49.511s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=62:ca:42:08:6d:78,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1 actions=output:"s1-eth4"
     cookie=0x0, duration=49.497s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth4",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=62:ca:42:08:6d:78,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2 actions=output:"s1-eth1"
     cookie=0x0, duration=40.001s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.3,arp_tpa=10.0.0.1,arp_op=2 actions=output:"s1-eth4"
     cookie=0x0, duration=34.858s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.3,arp_tpa=10.0.0.1,arp_op=1 actions=output:"s1-eth4"
     cookie=0x0, duration=34.844s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s1-eth4",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=f2:5e:27:69:32:00,arp_spa=10.0.0.1,arp_tpa=10.0.0.3,arp_op=2 actions=output:"s1-eth2"
     cookie=0x0, duration=54.555s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s1-eth4",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=62:ca:42:08:6d:78,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:"s1-eth1"
     cookie=0x0, duration=54.514s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=62:ca:42:08:6d:78,dl_dst=c2:9d:dc:1d:d4:93,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:"s1-eth4"
     cookie=0x0, duration=39.987s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s1-eth4",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=f2:5e:27:69:32:00,nw_src=10.0.0.1,nw_dst=10.0.0.3,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:"s1-eth2"
     cookie=0x0, duration=39.946s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s1-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,nw_src=10.0.0.3,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:"s1-eth4"
    [root@kunpeng82 demo1]# ovs-ofctl dump-flows s2
     cookie=0x0, duration=59.597s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s2-eth2",vlan_tci=0x0000,dl_src=62:ca:42:08:6d:78,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1 actions=output:"s2-eth1"
     cookie=0x0, duration=59.556s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s2-eth1",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=62:ca:42:08:6d:78,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2 actions=output:"s2-eth2"
    [root@kunpeng82 demo1]# ovs-ofctl dump-flows s3
     cookie=0x0, duration=58.050s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s3-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.3,arp_tpa=10.0.0.1,arp_op=2 actions=output:"s3-eth1"
     cookie=0x0, duration=52.921s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s3-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.3,arp_tpa=10.0.0.1,arp_op=1 actions=output:"s3-eth1"
     cookie=0x0, duration=52.866s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s3-eth1",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=f2:5e:27:69:32:00,arp_spa=10.0.0.1,arp_tpa=10.0.0.3,arp_op=2 actions=output:"s3-eth2"
     cookie=0x0, duration=58.009s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s3-eth1",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=f2:5e:27:69:32:00,nw_src=10.0.0.1,nw_dst=10.0.0.3,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:"s3-eth2"
     cookie=0x0, duration=57.996s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s3-eth2",vlan_tci=0x0000,dl_src=f2:5e:27:69:32:00,dl_dst=c2:9d:dc:1d:d4:93,nw_src=10.0.0.3,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:"s3-eth1"
    [root@kunpeng82 demo1]# ovs-ofctl dump-flows s4
     cookie=0x0, duration=6.190s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s4-eth2",vlan_tci=0x0000,dl_src=7a:eb:f1:92:31:a0,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.4,arp_tpa=10.0.0.1,arp_op=2 actions=output:"s4-eth1"
     cookie=0x0, duration=1.117s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s4-eth2",vlan_tci=0x0000,dl_src=7a:eb:f1:92:31:a0,dl_dst=c2:9d:dc:1d:d4:93,arp_spa=10.0.0.4,arp_tpa=10.0.0.1,arp_op=1 actions=output:"s4-eth1"
     cookie=0x0, duration=1.076s, table=0, n_packets=0, n_bytes=0, idle_timeout=60, priority=65535,arp,in_port="s4-eth1",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=7a:eb:f1:92:31:a0,arp_spa=10.0.0.1,arp_tpa=10.0.0.4,arp_op=2 actions=output:"s4-eth2"
     cookie=0x0, duration=6.150s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s4-eth1",vlan_tci=0x0000,dl_src=c2:9d:dc:1d:d4:93,dl_dst=7a:eb:f1:92:31:a0,nw_src=10.0.0.1,nw_dst=10.0.0.4,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:"s4-eth2"
     cookie=0x0, duration=6.136s, table=0, n_packets=2, n_bytes=196, idle_timeout=60, priority=65535,icmp,in_port="s4-eth2",vlan_tci=0x0000,dl_src=7a:eb:f1:92:31:a0,dl_dst=c2:9d:dc:1d:d4:93,nw_src=10.0.0.4,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:"s4-eth1"
    [root@kunpeng82 demo1]# 

    重新建立一个toop

       Topo.__init__(self, **opts)
            host1 = self.addHost('h1')
            host2 = self.addHost('h2')
            host3 = self.addHost('h3')
            host4 = self.addHost('h4')
        
            self.switch = {}
            for s in range(1,6):
                self.switch[s-1] = self.addSwitch('s%s' %(s))
            self.addLink(self.switch[0], self.switch[1])
            self.addLink(self.switch[0], self.switch[2])
            self.addLink(self.switch[0], self.switch[3])
            self.addLink(self.switch[4], self.switch[1])
            self.addLink(self.switch[4], self.switch[2])
            self.addLink(self.switch[4], self.switch[3])
                #Adding host
            self.addLink(self.switch[0], host1)
            self.addLink(self.switch[4], host2)
            self.addLink(self.switch[4], host3)
            self.addLink(self.switch[4], host4)
            
    topos = {'group':(lambda:MininetTopo())}
    [root@kunpeng82 demo1]#  mn --custom group2.py  --topo group
    *** Creating network
    *** Adding controller
    *** Adding hosts:
    h1 h2 h3 h4 
    *** Adding switches:
    s1 s2 s3 s4 s5 
    *** Adding links:
    (s1, h1) (s1, s2) (s1, s3) (s1, s4) (s5, h2) (s5, h3) (s5, h4) (s5, s2) (s5, s3) (s5, s4) 
    *** Configuring hosts
    h1 h2 h3 h4 
    *** Starting controller
    c0 
    *** Starting 5 switches
    s1 s2 s3 s4 s5 ...
    *** Starting CLI:
    不通了哦 mininet
    > h1 ping h2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. From 10.0.0.1 icmp_seq=1 Destination Host Unreachable From 10.0.0.1 icmp_seq=5 Destination Host Unreachable ^C --- 10.0.0.2 ping statistics --- 8 packets transmitted, 0 received, +2 errors, 100% packet loss, time 7241ms pipe 4 mininet> h1 ip n 10.0.0.2 dev h1-eth0 FAILED mininet>

    demo2

    [root@kunpeng82 demo1]# cat group2.py 
    from mininet.topo import Topo
    class MininetTopo(Topo):
        def __init__(self,**opts):
            Topo.__init__(self, **opts)
            host1 = self.addHost('h1')
            host2 = self.addHost('h2')
        
            self.switch = {}
            for s in range(1,3):
                self.switch[s-1] = self.addSwitch('s%s' %(s))
            self.addLink(self.switch[0], self.switch[1])
                #Adding host
            self.addLink(self.switch[0], host1)
            self.addLink(self.switch[1], host2)
            
    topos = {'group':(lambda:MininetTopo())}
    [root@kunpeng82 demo1]# 
    mininet> net
    h1 h1-eth0:s1-eth2
    h2 h2-eth0:s2-eth2
    s1 lo:  s1-eth1:s2-eth1 s1-eth2:h1-eth0
    s2 lo:  s2-eth1:s1-eth1 s2-eth2:h2-eth0
    c0
    mininet> h1 ping h2
    PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
    64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=54.3 ms
    64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=27.1 ms
    64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.198 ms
    64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.471 ms
    64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=0.035 ms
    64 bytes from 10.0.0.2: icmp_seq=6 ttl=64 time=0.069 ms
    64 bytes from 10.0.0.2: icmp_seq=7 ttl=64 time=0.048 ms
    64 bytes from 10.0.0.2: icmp_seq=8 ttl=64 time=0.027 ms
    64 bytes from 10.0.0.2: icmp_seq=9 ttl=64 time=0.027 ms
    64 bytes from 10.0.0.2: icmp_seq=10 ttl=64 time=0.027 ms

    demo3

    1、 采用arp proxy

    2、 环路检测保证同一个交换机中的某一个广播数据包只能有一个入口,从而防止成环

    from ryu.base import app_manager
    from ryu.controller import ofp_event
    from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet
    from ryu.lib.packet import ethernet
    from ryu.lib.packet import arp
    from ryu.lib.packet import ipv6
    from ryu.lib import mac
    
    
    class SimpleARPProxy13(app_manager.RyuApp):
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    
        def __init__(self, *args, **kwargs):
            super(SimpleARPProxy13, self).__init__(*args, **kwargs)
            self.mac_to_port = {}
            self.arp_table = {}
            self.sw = {}
    
        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            datapath = ev.msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            # install table-miss flow entry
            #
            # We specify NO BUFFER to max_len of the output action due to
            # OVS bug. At this moment, if we specify a lesser number, e.g.,
            # 128, OVS will send Packet-In with invalid buffer_id and
            # truncated packet data. In that case, we cannot output packets
            # correctly.
    
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                              ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)
            self.logger.info("switch:%s connected", datapath.id)
        def add_flow(self, datapath, priority, match, actions, buffer_id=None):
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                                 actions)]
            if buffer_id:
                mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                        priority=priority, match=match,
                                        instructions=inst)
            else:
                mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                        match=match, instructions=inst)
            datapath.send_msg(mod)
        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def _packet_in_handler(self, ev):
            msg = ev.msg
            datapath = msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            in_port = msg.match['in_port']
    
            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocols(ethernet.ethernet)[0]
            dst = eth.dst
            src = eth.src
            dpid = datapath.id
    
            self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
            if pkt.get_protocol(ipv6.ipv6):  # Drop the IPV6 Packets.
                match = parser.OFPMatch(eth_type=eth.ethertype)
                actions = []
                self.add_flow(datapath, 1, match, actions)
                return None
    
            arp_pkt = pkt.get_protocol(arp.arp)
    
            if arp_pkt:
                self.arp_table[arp_pkt.src_ip] = src  # ARP learning
                self.logger.info(" ARP: %s -> %s", arp_pkt.src_ip, arp_pkt.dst_ip)
                if self.arp_handler(msg):  # answer or drop
                    return None
    
            self.mac_to_port.setdefault(dpid, {})
            self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
    
            # Learn a mac address to avoid FLOOD next time.
            if src not in self.mac_to_port[dpid]:
                self.mac_to_port[dpid][src] = in_port
            #print self.mac_to_port
            if dst in self.mac_to_port[dpid]:
                out_port = self.mac_to_port[dpid][dst]
            #else:
                #if self.arp_handler(msg):  # 1:reply or drop;  0: flood
                #    return None
            else:
                print(self.mac_to_port[dpid])
                out_port = ofproto.OFPP_FLOOD
                print("Flood")
    
            actions = [parser.OFPActionOutput(out_port)]
    
            # Install a flow to avoid packet_in next time
            if out_port != ofproto.OFPP_FLOOD:
                self.logger.info(" install flow_mod:%s -> %s ", in_port, out_port)
    
                match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
                self.add_flow(datapath, 1, match, actions)
    
            data = None
            if msg.buffer_id == ofproto.OFP_NO_BUFFER:
                data = msg.data
            out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                      in_port=in_port, actions=actions, data=data)
    
            datapath.send_msg(out)
    
        def arp_handler(self, msg):
            datapath = msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            in_port = msg.match['in_port']
    
            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocols(ethernet.ethernet)[0]
            arp_pkt = pkt.get_protocol(arp.arp)
    
            if eth:
                eth_dst = eth.dst
                eth_src = eth.src
    
            # Break the loop for avoiding ARP broadcast storm
            if eth_dst == mac.BROADCAST_STR:  # and arp_pkt:
                arp_dst_ip = arp_pkt.dst_ip
                arp_src_ip = arp_pkt.src_ip
    
                if (datapath.id, arp_src_ip, arp_dst_ip) in self.sw:
                    # packet come back at different port.
                    if self.sw[(datapath.id, arp_src_ip, arp_dst_ip)] != in_port:
                        #drop
                        datapath.send_packet_out(in_port=in_port, actions=[])
                        return True
                else:
                    # self.sw.setdefault((datapath.id, eth_src, arp_dst_ip), None)
                    self.sw[(datapath.id, arp_src_ip, arp_dst_ip)] = in_port
                    print(self.sw)
                    self.mac_to_port.setdefault(datapath.id, {})
                    self.mac_to_port[datapath.id][eth_src] = in_port
    
            # Try to reply arp request
            if arp_pkt:
                if arp_pkt.opcode == arp.ARP_REQUEST:
                    hwtype = arp_pkt.hwtype
                    proto = arp_pkt.proto
                    hlen = arp_pkt.hlen
                    plen = arp_pkt.plen
                    arp_src_ip = arp_pkt.src_ip
                    arp_dst_ip = arp_pkt.dst_ip
                    if arp_dst_ip in self.arp_table:
                        actions = [parser.OFPActionOutput(in_port)]
                        ARP_Reply = packet.Packet()
    
                        ARP_Reply.add_protocol(ethernet.ethernet(
                            ethertype=eth.ethertype,
                            dst=eth_src,
                            src=self.arp_table[arp_dst_ip]))
                        ARP_Reply.add_protocol(arp.arp(
                            opcode=arp.ARP_REPLY,
                            src_mac=self.arp_table[arp_dst_ip],
                            src_ip=arp_dst_ip,
                            dst_mac=eth_src,
                            dst_ip=arp_src_ip))
    
                        ARP_Reply.serialize()
    
                        out = parser.OFPPacketOut(
                            datapath=datapath,
                            buffer_id=ofproto.OFP_NO_BUFFER,
                            in_port=ofproto.OFPP_CONTROLLER,
                            actions=actions, data=ARP_Reply.data)
                        datapath.send_msg(out)
                        print("ARP_Reply")
                        return True
            return False
    [root@kunpeng82 app]# 
  • 相关阅读:
    【Java高级工程师蜕变之路】008 Spring核心思想
    【Java高级工程师蜕变之路】003 MyBatis高级进阶
    【Java高级工程师蜕变之路】007 Spring基础回顾
    【Java高级工程师蜕变之路】006 ErrorContext的机制分析
    【Java高级工程师蜕变之路】002 自定义持久层框架
    【Java高级工程师蜕变之路】001 JDBC的问题分析
    如何配置mac环境下的JAVA_HOME
    【Java高级工程师蜕变之路】005 MyBatis插件及其应用
    【Java高级工程师蜕变之路】004 MyBatis源码剖析
    ConcurrentHashMap中的2的n次方幂上舍入方法
  • 原文地址:https://www.cnblogs.com/dream397/p/12986164.html
Copyright © 2011-2022 走看看