예제 #1
0
 def _control_plane_arp_handler(self, pkt_meta):
     ofmsgs = []
     pkt_meta.reparse_ip(ether.ETH_TYPE_ARP)
     arp_pkt = pkt_meta.pkt.get_protocol(arp.arp)
     if arp_pkt is None:
         return ofmsgs
     src_ip = ipaddress.IPv4Address(btos(arp_pkt.src_ip))
     dst_ip = ipaddress.IPv4Address(btos(arp_pkt.dst_ip))
     vlan = pkt_meta.vlan
     if vlan.from_connected_to_vip(src_ip, dst_ip):
         opcode = arp_pkt.opcode
         port = pkt_meta.port
         eth_src = pkt_meta.eth_src
         vid = self._vlan_vid(vlan, port)
         if opcode == arp.ARP_REQUEST:
             ofmsgs.extend(
                 self._add_host_fib_route(vlan, src_ip))
             ofmsgs.extend(self._update_nexthop(
                 vlan, port, eth_src, src_ip))
             arp_reply = valve_packet.arp_reply(
                 vid, vlan.faucet_mac, eth_src, dst_ip, src_ip)
             ofmsgs.append(
                 valve_of.packetout(port.number, arp_reply.data))
             self.logger.info(
                 'Responded to ARP request for %s from %s (%s) on VLAN %u' % (
                     dst_ip, src_ip, eth_src, vlan.vid))
         elif (opcode == arp.ARP_REPLY and
               pkt_meta.eth_dst == vlan.faucet_mac):
             ofmsgs.extend(
                 self._update_nexthop(vlan, port, eth_src, src_ip))
             self.logger.info(
                 'ARP response %s (%s) on VLAN %u' % (
                     src_ip, eth_src, vlan.vid))
     return ofmsgs
예제 #2
0
파일: vlan.py 프로젝트: KookyMonster/faucet
    def __init__(self, _id, dp_id, conf=None):
        super(VLAN, self).__init__(_id, conf)
        self.dp_id = dp_id
        self.tagged = []
        self.untagged = []
        self.dyn_host_cache = {}
        self.dyn_faucet_vips_by_ipv = collections.defaultdict(list)
        self.dyn_routes_by_ipv = collections.defaultdict(dict)
        self.dyn_neigh_cache_by_ipv = collections.defaultdict(dict)
        self.dyn_ipvs = []

        if self.faucet_vips:
            self.faucet_vips = [
                ipaddress.ip_interface(btos(ip)) for ip in self.faucet_vips
            ]
            for faucet_vip in self.faucet_vips:
                self.dyn_faucet_vips_by_ipv[faucet_vip.version].append(
                    faucet_vip)
            self.dyn_ipvs = list(self.dyn_faucet_vips_by_ipv.keys())

        if self.bgp_as:
            assert self.bgp_port
            assert ipaddress.IPv4Address(btos(self.bgp_routerid))
            for neighbor_ip in self.bgp_neighbor_addresses:
                assert ipaddress.ip_address(btos(neighbor_ip))
            assert self.bgp_neighbor_as

        if self.routes:
            self.routes = [route['route'] for route in self.routes]
            for route in self.routes:
                ip_gw = ipaddress.ip_address(btos(route['ip_gw']))
                ip_dst = ipaddress.ip_network(btos(route['ip_dst']))
                assert ip_gw.version == ip_dst.version
                self.dyn_routes_by_ipv[ip_gw.version][ip_dst] = ip_gw
예제 #3
0
    def _bgp_route_handler(self, path_change, vlan):
        """Handle a BGP change event.

        Args:
            path_change (ryu.services.protocols.bgp.bgpspeaker.EventPrefix): path change
            vlan (vlan): Valve VLAN this path change was received for.
        """
        prefix = ipaddress.ip_network(btos(path_change.prefix))
        nexthop = ipaddress.ip_address(btos(path_change.nexthop))
        withdraw = path_change.is_withdraw
        flowmods = []
        valve = self._valves[vlan.dp_id]
        if vlan.is_faucet_vip(nexthop):
            self.logger.error('BGP nexthop %s for prefix %s cannot be us',
                              nexthop, prefix)
            return
        if vlan.ip_in_vip_subnet(nexthop) is None:
            self.logger.error(
                'BGP nexthop %s for prefix %s is not a connected network',
                nexthop, prefix)
            return

        if withdraw:
            self.logger.info('BGP withdraw %s nexthop %s', prefix, nexthop)
            flowmods = valve.del_route(vlan, prefix)
        else:
            self.logger.info('BGP add %s nexthop %s', prefix, nexthop)
            flowmods = valve.add_route(vlan, nexthop, prefix)
        if flowmods:
            self._send_flow_msgs(vlan.dp_id, flowmods)
예제 #4
0
 def _control_plane_arp_handler(self, pkt_meta, arp_pkt):
     src_ip = ipaddress.IPv4Address(btos(arp_pkt.src_ip))
     dst_ip = ipaddress.IPv4Address(btos(arp_pkt.dst_ip))
     vlan = pkt_meta.vlan
     opcode = arp_pkt.opcode
     ofmsgs = []
     if vlan.from_connected_to_vip(src_ip, dst_ip):
         port = pkt_meta.port
         eth_src = pkt_meta.eth_src
         if opcode == arp.ARP_REQUEST:
             ofmsgs.extend(self._add_host_fib_route(vlan, src_ip))
             ofmsgs.extend(self._update_nexthop(vlan, port, eth_src,
                                                src_ip))
             vid = self._vlan_vid(vlan, port)
             arp_reply = valve_packet.arp_reply(vid, self.faucet_mac,
                                                eth_src, dst_ip, src_ip)
             ofmsgs.append(valve_of.packetout(port.number, arp_reply.data))
             self.logger.info(
                 'Responded to ARP request for %s from %s (%s)', dst_ip,
                 src_ip, eth_src)
         elif (opcode == arp.ARP_REPLY
               and pkt_meta.eth_dst == self.faucet_mac):
             ofmsgs.extend(self._update_nexthop(vlan, port, eth_src,
                                                src_ip))
             self.logger.info('ARP response %s (%s)', src_ip, eth_src)
     return ofmsgs
예제 #5
0
 def _control_plane_icmpv6_handler(self, pkt_meta, ipv6_pkt, icmpv6_pkt):
     vlan = pkt_meta.vlan
     src_ip = ipaddress.IPv6Address(btos(ipv6_pkt.src))
     dst_ip = ipaddress.IPv6Address(btos(ipv6_pkt.dst))
     icmpv6_type = icmpv6_pkt.type_
     ofmsgs = []
     if vlan.ip_in_vip_subnet(src_ip):
         in_port = pkt_meta.port.number
         vid = self._vlan_vid(vlan, in_port)
         eth_src = pkt_meta.eth_src
         if icmpv6_type == icmpv6.ND_NEIGHBOR_SOLICIT:
             solicited_ip = btos(icmpv6_pkt.data.dst)
             if vlan.is_faucet_vip(ipaddress.ip_address(solicited_ip)):
                 ofmsgs.extend(self._add_host_fib_route(vlan, src_ip))
                 nd_reply = valve_packet.nd_reply(self.faucet_mac, eth_src,
                                                  vid, solicited_ip, src_ip,
                                                  ipv6_pkt.hop_limit)
                 ofmsgs.append(valve_of.packetout(in_port, nd_reply.data))
                 self.logger.info(
                     'Responded to ND solicit for %s to %s (%s)',
                     solicited_ip, src_ip, eth_src)
         elif icmpv6_type == icmpv6.ND_NEIGHBOR_ADVERT:
             ofmsgs.extend(
                 self._update_nexthop(vlan, in_port, eth_src, src_ip))
             self.logger.info('ND advert %s (%s)', src_ip, eth_src)
         elif vlan.from_connected_to_vip(src_ip, dst_ip):
             if (icmpv6_type == icmpv6.ICMPV6_ECHO_REQUEST
                     and pkt_meta.eth_dst == self.faucet_mac):
                 icmpv6_echo_reply = valve_packet.icmpv6_echo_reply(
                     self.faucet_mac, eth_src, vid, dst_ip, src_ip,
                     ipv6_pkt.hop_limit, icmpv6_pkt.data.id,
                     icmpv6_pkt.data.seq, icmpv6_pkt.data.data)
                 ofmsgs.append(
                     valve_of.packetout(in_port, icmpv6_echo_reply.data))
     return ofmsgs
예제 #6
0
 def _control_plane_icmp_handler(self, pkt_meta, ipv4_pkt, icmp_pkt):
     src_ip = ipaddress.IPv4Address(btos(ipv4_pkt.src))
     dst_ip = ipaddress.IPv4Address(btos(ipv4_pkt.dst))
     vlan = pkt_meta.vlan
     icmpv4_type = icmp_pkt.type
     ofmsgs = []
     if vlan.from_connected_to_vip(src_ip, dst_ip):
         if (icmpv4_type == icmp.ICMP_ECHO_REQUEST
                 and pkt_meta.eth_dst == self.faucet_mac):
             port = pkt_meta.port
             vid = self._vlan_vid(vlan, port)
             echo_reply = valve_packet.echo_reply(vid, self.faucet_mac,
                                                  pkt_meta.eth_src, dst_ip,
                                                  src_ip, icmp_pkt.data)
             ofmsgs.append(valve_of.packetout(port.number, echo_reply.data))
     return ofmsgs
예제 #7
0
    def add_host_fib_route_from_pkt(self, pkt_meta):
        """Add a host FIB route given packet from host.

        Args:
            pkt_meta (PacketMeta): received packet.
        Returns:
            list: OpenFlow messages.
        """
        ip_pkt = self._ip_pkt(pkt_meta.pkt)
        ofmsgs = []
        if ip_pkt:
            src_ip = ipaddress.ip_address(btos(ip_pkt.src))
            if src_ip and pkt_meta.vlan.ip_in_vip_subnet(src_ip):
                now = time.time()
                nexthop_fresh = self._nexthop_fresh(pkt_meta.vlan, src_ip, now)
                self._update_nexthop_cache(pkt_meta.vlan, pkt_meta.eth_src,
                                           src_ip)
                if not nexthop_fresh:
                    if self.use_group_table:
                        ofmsgs.extend(
                            self._update_nexthop_group(False, src_ip,
                                                       pkt_meta.vlan,
                                                       pkt_meta.port,
                                                       pkt_meta.eth_src))
                    ofmsgs.extend(
                        self._add_host_fib_route(pkt_meta.vlan, src_ip))
        return ofmsgs
예제 #8
0
 def control_plane_handler(self, pkt_meta):
     pkt = pkt_meta.pkt
     ipv6_pkt = pkt.get_protocol(ipv6.ipv6)
     if ipv6_pkt is not None:
         icmp_replies = self._control_plane_icmpv6_handler(
             pkt_meta, ipv6_pkt)
         if icmp_replies:
             return icmp_replies
         dst_ip = ipaddress.IPv6Address(btos(ipv6_pkt.dst))
         return self._proactive_resolve_neighbor([pkt_meta.vlan], dst_ip)
     return []
예제 #9
0
 def control_plane_handler(self, pkt_meta):
     ipv4_pkt = pkt_meta.pkt.get_protocol(ipv4.ipv4)
     if ipv4_pkt is None:
         return self._control_plane_arp_handler(pkt_meta)
     else:
         icmp_replies = self._control_plane_icmp_handler(pkt_meta, ipv4_pkt)
         if icmp_replies:
             return icmp_replies
         dst_ip = ipaddress.IPv4Address(btos(ipv4_pkt.dst))
         vlan = pkt_meta.vlan
         return self._proactive_resolve_neighbor([vlan], dst_ip)
     return []
예제 #10
0
 def _control_plane_icmp_handler(self, pkt_meta, ipv4_pkt):
     ofmsgs = []
     src_ip = ipaddress.IPv4Address(btos(ipv4_pkt.src))
     dst_ip = ipaddress.IPv4Address(btos(ipv4_pkt.dst))
     vlan = pkt_meta.vlan
     if vlan.from_connected_to_vip(src_ip, dst_ip):
         if pkt_meta.eth_dst != vlan.faucet_mac:
             return ofmsgs
         if ipv4_pkt.proto != inet.IPPROTO_ICMP:
             return ofmsgs
         pkt_meta.reparse_all()
         icmp_pkt = pkt_meta.pkt.get_protocol(icmp.icmp)
         if icmp_pkt is None:
             return ofmsgs
         if icmp_pkt.type == icmp.ICMP_ECHO_REQUEST:
             port = pkt_meta.port
             vid = self._vlan_vid(vlan, port)
             echo_reply = valve_packet.echo_reply(vid, vlan.faucet_mac,
                                                  pkt_meta.eth_src, dst_ip,
                                                  src_ip, icmp_pkt.data)
             ofmsgs.append(valve_of.packetout(port.number, echo_reply.data))
     return ofmsgs
예제 #11
0
    def __init__(self, _id, dp_id, conf=None):
        if conf is None:
            conf = {}
        self._id = _id
        self.dp_id = dp_id
        valve_util.check_unknown_conf(conf, self.defaults)
        self.update(conf)
        self.set_defaults()
        self._id = _id
        self.tagged = []
        self.untagged = []
        self.dyn_ipv4_routes = {}
        self.dyn_ipv6_routes = {}
        self.dyn_arp_cache = {}
        self.dyn_nd_cache = {}
        self.dyn_host_cache = {}

        if self.faucet_vips:
            self.faucet_vips = [
                ipaddress.ip_interface(btos(ip)) for ip in self.faucet_vips
            ]

        if self.bgp_as:
            assert self.bgp_port
            assert ipaddress.IPv4Address(btos(self.bgp_routerid))
            for neighbor_ip in self.bgp_neighbor_addresses:
                assert ipaddress.ip_address(btos(neighbor_ip))
            assert self.bgp_neighbor_as

        if self.routes:
            self.routes = [route['route'] for route in self.routes]
            for route in self.routes:
                ip_gw = ipaddress.ip_address(btos(route['ip_gw']))
                ip_dst = ipaddress.ip_network(btos(route['ip_dst']))
                assert ip_gw.version == ip_dst.version
                if ip_gw.version == 4:
                    self.ipv4_routes[ip_dst] = ip_gw
                else:
                    self.ipv6_routes[ip_dst] = ip_gw
예제 #12
0
def ipv6_solicited_node_from_ucast(ucast):
    """Return IPv6 solicited node multicast address from IPv6 unicast address.

    See RFC 3513 section 2.7.1.

    Args:
       ucast (ipaddress.IPv6Address): IPv6 unicast address.
    Returns:
       ipaddress.IPv6Address: IPv6 solicited node multicast address.
    """
    link_mcast_prefix = ipaddress.ip_interface(btos('ff02::1:ff00:0/104'))
    mcast_bytes = link_mcast_prefix.packed[:13] + ucast.packed[-3:]
    link_mcast = ipaddress.IPv6Address(mcast_bytes)
    return link_mcast
예제 #13
0
    def add_host_fib_route_from_pkt(self, pkt_meta):
        """Add a host FIB route given packet from host.

        Args:
            pkt_meta (PacketMeta): received packet.
        Returns:
            list: OpenFlow messages.
        """
        ip_pkt = self._ip_pkt(pkt_meta.pkt)
        ofmsgs = []
        if ip_pkt:
            src_ip = ipaddress.ip_address(btos(ip_pkt.src))
            if src_ip and pkt_meta.vlan.ip_in_vip_subnet(src_ip):
                ofmsgs.extend(
                    self._add_host_fib_route(pkt_meta.vlan, src_ip))
                ofmsgs.extend(self._update_nexthop(
                    pkt_meta.vlan, pkt_meta.port, pkt_meta.eth_src, src_ip))
        return ofmsgs
예제 #14
0
 def _control_plane_icmpv6_handler(self, pkt_meta, ipv6_pkt):
     ofmsgs = []
     src_ip = ipaddress.IPv6Address(btos(ipv6_pkt.src))
     dst_ip = ipaddress.IPv6Address(btos(ipv6_pkt.dst))
     vlan = pkt_meta.vlan
     if vlan.ip_in_vip_subnet(src_ip):
         # Must be ICMPv6 and have no extended headers.
         if ipv6_pkt.nxt != inet.IPPROTO_ICMPV6:
             return ofmsgs
         if ipv6_pkt.ext_hdrs:
             return ofmsgs
         # Explicitly ignore messages to all notes.
         if dst_ip == valve_packet.IPV6_ALL_NODES:
             return ofmsgs
         pkt_meta.reparse_ip(self.ETH_TYPE, payload=32)
         icmpv6_pkt = pkt_meta.pkt.get_protocol(icmpv6.icmpv6)
         if icmpv6_pkt is None:
             return ofmsgs
         icmpv6_type = icmpv6_pkt.type_
         if (ipv6_pkt.hop_limit != valve_packet.IPV6_MAX_HOP_LIM and
                 icmpv6_type != icmpv6.ICMPV6_ECHO_REQUEST):
             return ofmsgs
         port = pkt_meta.port
         vid = self._vlan_vid(vlan, port)
         eth_src = pkt_meta.eth_src
         if icmpv6_type == icmpv6.ND_NEIGHBOR_SOLICIT:
             solicited_ip = btos(icmpv6_pkt.data.dst)
             if vlan.is_faucet_vip(ipaddress.ip_address(solicited_ip)):
                 ofmsgs.extend(
                     self._add_host_fib_route(vlan, src_ip))
                 ofmsgs.extend(self._update_nexthop(
                     vlan, port, eth_src, src_ip))
                 nd_reply = valve_packet.nd_advert(
                     vid, vlan.faucet_mac, eth_src,
                     solicited_ip, src_ip)
                 ofmsgs.append(
                     valve_of.packetout(port.number, nd_reply.data))
                 self.logger.info(
                     'Responded to ND solicit for %s to %s (%s) on VLAN %u' % (
                         solicited_ip, src_ip, eth_src, vlan.vid))
         elif icmpv6_type == icmpv6.ND_NEIGHBOR_ADVERT:
             ofmsgs.extend(self._update_nexthop(
                 vlan, port, eth_src, src_ip))
             self.logger.info(
                 'ND advert %s (%s) on VLAN %u' % (
                     src_ip, eth_src, vlan.vid))
         elif icmpv6_type == icmpv6.ND_ROUTER_SOLICIT:
             link_local_vips, other_vips = self._link_and_other_vips(vlan)
             for vip in link_local_vips:
                 if src_ip in vip.network:
                     ofmsgs.extend(
                         self._add_host_fib_route(vlan, src_ip))
                     ofmsgs.extend(self._update_nexthop(
                         vlan, port, eth_src, src_ip))
                     ra_advert = valve_packet.router_advert(
                         vlan, vid, vlan.faucet_mac, eth_src,
                         vip.ip, src_ip, other_vips)
                     ofmsgs.append(
                         valve_of.packetout(port.number, ra_advert.data))
                     self.logger.info(
                         'Responded to RS solicit from %s (%s) to VIP %s on VLAN %u' % (
                             src_ip, eth_src, vip, vlan.vid))
                     break
         elif icmpv6_type == icmpv6.ICMPV6_ECHO_REQUEST:
             if (vlan.from_connected_to_vip(src_ip, dst_ip) and
                     pkt_meta.eth_dst == vlan.faucet_mac):
                 icmpv6_echo_reply = valve_packet.icmpv6_echo_reply(
                     vid, vlan.faucet_mac, eth_src,
                     dst_ip, src_ip, ipv6_pkt.hop_limit,
                     icmpv6_pkt.data.id, icmpv6_pkt.data.seq,
                     icmpv6_pkt.data.data)
                 ofmsgs.append(
                     valve_of.packetout(port.number, icmpv6_echo_reply.data))
     return ofmsgs
예제 #15
0
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import ipaddress

from ryu.lib import mac
from ryu.lib.packet import arp, ethernet, icmp, icmpv6, ipv4, ipv6, stream_parser, packet, vlan
from ryu.ofproto import ether
from ryu.ofproto import inet

from valve_util import btos

IPV6_ALL_NODES_MCAST = '33:33:00:00:00:01'
IPV6_ALL_ROUTERS_MCAST = '33:33:00:00:00:02'
IPV6_LINK_LOCAL = ipaddress.IPv6Network(btos('fe80::/10'))
IPV6_ALL_NODES = ipaddress.IPv6Address(btos('ff02::1'))


def mac_addr_is_unicast(mac_addr):
    """Returns True if mac_addr is a unicast Ethernet address.

    Args:
        mac_addr (str): MAC address.
    Returns:
        bool: True if a unicast Ethernet address.
    """
    msb = mac_addr.split(':')[0]
    return msb[-1] in '02468aAcCeE'