def egress_src_dest_pairs_policy(self): policies = [] for src_dest_pair in self.nib.get_egress_src_dest_pairs(): (src_ip, dst_ip) = src_dest_pair # Convert dst_ip to its real form. First find out what the egress switch actually is: for ap in self.nib.alternate_paths(): if NetUtils.ip_in_network(dst_ip, ap["ithaca"]): switch = "ithaca" imaginary_net = ap["ithaca"] elif NetUtils.ip_in_network(dst_ip, ap["nyc"]): switch = "nyc" imaginary_net = ap["nyc"] real_net = self.nib.actual_net_for(switch) dst_host = NetUtils.host_of_ip(dst_ip, imaginary_net) new_dest_ip = NetUtils.ip_for_network(real_net, dst_host) # If it's not in the ARP cache, it already has an ARP request on the way so ignore it for now. if self.nib.learned_ip(new_dest_ip): direct_net_port = self.nib.port_for_ip(new_dest_ip) new_src_ip = self.nib.translate_alternate_net(src_ip) output_actions = SetIP4Src(new_src_ip) >> SetIP4Dst(new_dest_ip) >> Send(direct_net_port) policies.append( Filter(SwitchEq(self.nib.switch_to_dpid(switch)) & Policies.is_ip_from_to(src_ip, dst_ip)) >> output_actions ) return Union(policies)
def policy(self): policies = [] for switch in self.nib.switches_present(): dpid = self.nib.switch_to_dpid(switch) # In normal mode, we capture ARP requests for IP's that don't really exist. You can # think of them as symbolic links to the real IP. We capture .1 address of # each of the endpoint networks, plus any real hosts on the net # And we capture ARP requests for the alternate paths. These will always be for # hosts that have no real estate on the imaginary link, as in 192.168.156.100 along # the 192.168.156.* imaginary network. This will be translated to the real net 192.168.56.100 # Note: only the routers actually send these requests, not end hosts, who always send them # to a default gateway. for ap in self.nib.alternate_paths(): (net, mask) = NetUtils.net_mask(ap[switch]) policies.append(Filter(Policies.at_switch(dpid) & Policies.is_arp() & IP4DstEq(net,mask)) >> Policies.send_to_controller()) return Union(policies)
def ingress_src_dest_pairs_policy(self): policies = [] for src_dest_pair in self.nib.get_ingress_src_dest_pairs(): (src_ip, dst_ip) = src_dest_pair switch = self.nib.switch_for_ip(src_ip) dpid = self.nib.switch_to_dpid(switch) port = self.nib.port_for_ip(src_ip) src_host = NetUtils.host_of_ip(src_ip, self.nib.actual_net_for(switch)) # If this is going to the preferred network, write a rule choosing the # correct route here. opposite_switch = self.nib.opposite_switch(switch) if NetUtils.ip_in_network(dst_ip, self.nib.actual_net_for(opposite_switch)): # Get host from src_ip src_pref_net = self.nib.preferred_net(switch) new_src = NetUtils.ip_for_network(src_pref_net, src_host) dest_host = NetUtils.host_of_ip(dst_ip, self.nib.actual_net_for(opposite_switch)) new_dest = NetUtils.ip_for_network(self.nib.preferred_net(opposite_switch), dest_host) router_port = self.nib.router_port_for_switch(switch) output_actions = SetIP4Src(new_src) >> SetIP4Dst(new_dest) >> Send(router_port) policies.append( Filter(Policies.at_switch_port(dpid, port) & Policies.is_ip_from_to(src_ip, dst_ip)) >> output_actions ) else: # It's a direct path. Find the path first. for ap in self.nib.alternate_paths(): if NetUtils.ip_in_network(dst_ip, ap[opposite_switch]): alternate_path = ap new_src = NetUtils.ip_for_network(alternate_path[switch], src_host) router_port = self.nib.router_port_for_switch(switch) output_actions = SetIP4Src(new_src) >> Send(router_port) policies.append( Filter(Policies.at_switch_port(dpid, port) & Policies.is_ip_from_to(src_ip, dst_ip)) >> output_actions ) return Union(policies)
def capture_new_source_dest_pairs_policy(self): policies = [] for switch in self.nib.switches_present(): dpid = self.nib.switch_to_dpid(switch) for endhost in self.nib.get_endhosts(switch): (host, host_port, host_mac, host_ip) = endhost opposite_switch = self.nib.opposite_switch(switch) dest_cdr = self.nib.actual_net_for(opposite_switch) (dest_net, dest_mask) = NetUtils.net_mask(dest_cdr) # Note we really don't have to test for source IP, but it's extra security policies.append( Filter( Policies.at_switch_port(dpid, host_port) & Policies.is_ip() & IP4SrcEq(host_ip) & IP4DstEq(dest_net, dest_mask) & self.destination_not_known_host_on_net(host_ip, dest_cdr) ) >> Policies.send_to_controller() ) for ap in self.nib.alternate_paths(): dest_cdr = ap[opposite_switch] (dest_net, dest_mask) = NetUtils.net_mask(dest_cdr) policies.append( Filter( Policies.at_switch_port(dpid, host_port) & Policies.is_ip() & IP4SrcEq(host_ip) & IP4DstEq(dest_net, dest_mask) & self.destination_not_known_host_on_net(host_ip, dest_cdr) ) >> Policies.send_to_controller() ) # Now handle incoming packets for all our home networks. We need to learn # those (src, dest) pairs as well for ap in self.nib.alternate_paths(): dest_cdr = ap[switch] (dest_net, dest_mask) = NetUtils.net_mask(dest_cdr) policies.append( Filter(Policies.is_ip() & IP4DstEq(dest_net, dest_mask) & self.src_dest_pair_not_learned(dest_cdr)) >> Policies.send_to_controller() ) return Union(policies)
def policy(self): policies = [] for switch in self.nib.switches_present(): dpid = self.nib.switch_to_dpid(switch) # The router interface is no different than a regular host with regard to intranet traffic. learned_host_ports = [ p for (_, p, _, _) in self.nib.get_endhosts(switch)] learned_host_ports.append( self.nib.router_port_for_switch(switch) ) for src_endhost_port in learned_host_ports: output_actions = [ Send(p) for p in self.nib.ports_on_switch(switch) if p != src_endhost_port ] policies.append( Filter (Policies.at_switch_port(dpid, src_endhost_port) & EthDstEq("ff:ff:ff:ff:ff:ff")) >> Seq(output_actions) ) return Union(policies)
def policy(self): # One rule sends all traffic from unlearned ports to controller. is_at_unlearned_port = [] unlearned_ports = self.nib.get_unlearned_ports() for switch, ports in unlearned_ports.iteritems(): dpid = self.nib.switch_to_dpid(switch) for port in ports: is_at_unlearned_port.append(Policies.at_switch_port(dpid,port)) policies = [ Filter(Or(is_at_unlearned_port)) >> Policies.send_to_controller() ] # Output rules for each pair of learned endhosts so intranet traffic can be handled nicely on # the switch. # TODO: If the app is restarted but hosts are hanging onto ARP cache entries, they won't be able # to get packets to each other. This is hard to handle because a "Port = n AND Dest Net = this" # might have overlap with other rules ... I think # Therefore, I'm letting this go for now because (1) intranet host # traffic is relatively rare (2) ARP cache entries usually timeout in 10 minutes anyway. # L2Switch.policy. for switch in self.nib.switches_present(): dpid = self.nib.switch_to_dpid(switch) # The router interface is no different than a regular host with regard to intranet traffic. all_hosts = copy.deepcopy(self.nib.get_endhosts(switch)) all_hosts.append( (None, self.nib.router_port_for_switch(switch) , None, self.nib.router_ip_for_switch(switch) ) ) for src_endhost in all_hosts: (_, src_port, _, src_ip) = src_endhost for dst_endhost in all_hosts: (_, dst_port, _, dst_ip) = dst_endhost # No rule for a host to itself, obviously if src_ip != dst_ip: policies.append( Filter(Policies.is_ip_from_to(src_ip, dst_ip) & Policies.at_switch_port(dpid, src_port) ) >> Send(dst_port) ) policies.append( Filter(Policies.is_arp_from_to(src_ip, dst_ip) & Policies.at_switch_port(dpid, src_port) ) >> Send(dst_port) ) return Union(policies)
def router_learning_policy(self): # In the intial config, grab all ARP replies for ourselves return Filter( Policies.is_arp() ) >> Policies.send_to_controller()