def update_policy(self, pkt): if self.group_by: # MATCH ON PROVIDED GROUP_BY pred = match([(field, pkt[field]) for field in self.group_by]) else: # OTHERWISE, MATCH ON ALL AVAILABLE GROUP_BY pred = match([(field, pkt[field]) for field in pkt.available_group_by()]) # INCREMENT THE NUMBER OF TIMES MATCHING PKT SEEN try: self.seen[pred] += 1 except KeyError: self.seen[pred] = 1 if self.seen[pred] == self.limit: val = {h: pkt[h] for h in self.group_by} self.done.append(match(val)) self.policy = ~union(self.done)
def _commute_test(self, act, pkts): from pyretic.core.language import modify, drop, identity, Controller, CountBucket, DerivedPolicy, match while isinstance(act, DerivedPolicy): act = act.policy if act == identity: return pkts elif act == drop: return drop elif act == Controller or isinstance(act, CountBucket): return identity elif isinstance(act, modify): new_match_dict = {} if pkts == identity: return identity elif pkts == drop: return drop for f, v in pkts.map.iteritems(): if f in act.map and act.map[f] == v: continue elif f in act.map and act.map[f] != v: return drop else: new_match_dict[f] = v if len(new_match_dict) == 0: return identity return match(**new_match_dict) else: # TODO (cole) use compile error. # TODO (cole) what actions are allowable? raise TypeError
def _commute_test(act, pkts): while isinstance(act, DerivedPolicy): act = act.policy if act == identity: return pkts elif act == Controller or isinstance(act, CountBucket): return identity elif isinstance(act, modify): new_match_dict = {} if pkts == identity: return identity elif pkts == drop: return drop for f, v in pkts.map.iteritems(): if f in act.map and act.map[f] == v: continue elif f in act.map and act.map[f] != v: return drop else: new_match_dict[f] = v if len(new_match_dict) == 0: return identity return match(**new_match_dict) else: raise TypeError
def use_explicit_switches(pol): """ Ensure every switch in the network gets reflected in the policy sent to netkat. This is because netkat generates a separate copy of the policy per switch, and it is necessary for it to know that a switch appears in the policy through the policy itself.""" from pyretic.core.language import match, identity pred_policy = None used_cnt = switch_cnt if switch_cnt else 0 for i in range(1, used_cnt + 1): if pred_policy is None: pred_policy = match(switch = i) else: pred_policy |= match(switch = i) if pred_policy is None: pred_policy = identity return pred_policy >> pol
def _commute_test(act, pkts): from pyretic.core.language import (match, modify, drop, identity, Controller, CountBucket, DerivedPolicy, PathBucket) from pyretic.lib.netflow import NetflowBucket while isinstance(act, DerivedPolicy): act = act.policy if act == identity: return pkts elif (act == Controller or isinstance(act, PathBucket) or isinstance(act, NetflowBucket)): return identity elif isinstance(act, CountBucket): """ TODO(ngsrinivas): inspect which possibility is best """ return identity # return pkts elif isinstance(act, modify): new_match_dict = {} if pkts == identity: return identity elif pkts == drop: return drop for f, v in pkts.map.iteritems(): if f in act.map and act.map[f] == v: continue elif f in act.map and act.map[f] != v: return drop else: new_match_dict[f] = v if len(new_match_dict) == 0: return identity return match(**new_match_dict) else: raise TypeError
def set_network(self, network): super(egress_network,self).set_network(network) updated_egresses = network.topology.egress_locations() if not self.egresses == updated_egresses: self.egresses = updated_egresses self.policy = parallel([match(switch=l.switch, outport=l.port_no) for l in self.egresses])
def set_network(self, network): super(ingress_network, self).set_network(network) updated_egresses = network.topology.egress_locations() if not self.egresses == updated_egresses: self.egresses = updated_egresses self.policy = parallel([ match(switch=l.switch, inport=l.port_no) for l in self.egresses ])
def eval(self,pkt): if not self.limit is None: if self.group_by: # MATCH ON PROVIDED GROUP_BY pred = match([(field,pkt[field]) for field in self.group_by]) else: # OTHERWISE, MATCH ON ALL AVAILABLE GROUP_BY pred = match([(field,pkt[field]) for field in pkt.available_group_by()]) # INCREMENT THE NUMBER OF TIMES MATCHING PKT SEEN try: self.seen[pred] += 1 except KeyError: self.seen[pred] = 1 if self.seen[pred] > self.limit: return set() self.fwd_bucket.eval(pkt) return {pkt}
def eval(self, pkt): if not self.limit is None: if self.group_by: # MATCH ON PROVIDED GROUP_BY pred = match([(field, pkt[field]) for field in self.group_by]) else: # OTHERWISE, MATCH ON ALL AVAILABLE GROUP_BY pred = match([(field, pkt[field]) for field in pkt.available_group_by()]) # INCREMENT THE NUMBER OF TIMES MATCHING PKT SEEN try: self.seen[pred] += 1 except KeyError: self.seen[pred] = 1 if self.seen[pred] > self.limit: return set() self.fwd_bucket.eval(pkt) return {pkt}
def update_aggregate(self,pkt): if self.group_by: from pyretic.core.language import match groups = set(self.group_by) & set(pkt.available_fields()) pred = match([(field,pkt[field]) for field in groups]) try: self.aggregate[pred] = self.aggregator(self.aggregate[pred],pkt) except KeyError: self.aggregate[pred] = self.aggregator(0,pkt) else: self.aggregate = self.aggregator(self.aggregate,pkt)
def update_policy(self, pkt): pred = self.get_pred_from_pkt(pkt) # INCREMENT THE NUMBER OF TIMES MATCHING PKT SEEN try: self.seen[pred] += 1 except KeyError: self.seen[pred] = 1 if self.seen[pred] == self.limit: val = {h: pkt[h] for h in self.group_by} self.done.append(match(val)) self.policy = ~union(self.done)
def update_policy(self,pkt): pred = self.get_pred_from_pkt(pkt) # INCREMENT THE NUMBER OF TIMES MATCHING PKT SEEN try: self.seen[pred] += 1 except KeyError: self.seen[pred] = 1 if self.seen[pred] == self.limit: val = {h : pkt[h] for h in self.group_by} self.done.append(match(val)) self.policy = ~union(self.done)
def create_match(pattern, switch_id, vlan_offset_nbits): from pyretic.core.language import match def __reverse_mac__(m): return ':'.join(m.split(':')[::-1]) if switch_id > 0: match_map = {'switch': switch_id} else: match_map = {} vlan_processed = False for k, v in pattern.items(): if v is not None: if k == 'dlSrc' or k == 'dlDst': """ TODO: NetKat returns MAC addresses reversed. """ match_map[field_map[k]] = MAC(__reverse_mac__(v)) elif k == 'dlVlan' or k == 'dlVlanPcp': """ Reset `None` value for VLAN matches, if any. """ if not vlan_processed: if (('dlVlan' in pattern and pattern['dlVlan'] == VLAN_NONE_VALUE) and ('dlVlanPcp' in pattern and pattern['dlVlanPcp'] == VLAN_PCP_NONE_VALUE)): match_map['vlan_id'] = None match_map['vlan_pcp'] = None else: def get_num(v): # HACK! Sometimes, one of the fields has a value # `None`. TODO: Must understand why this happens, # because the compiler/runtime always set vlan_id # and vlan_pcp together. May well lead to bugs in # future! return v if not v is None else 0 match_map['vlan_id'] = get_num(pattern['dlVlan']) match_map['vlan_pcp'] = get_num(pattern['dlVlanPcp']) vlan_processed = True else: match_map[field_map[k]] = v # HACK! NetKat doesn't return vlan_pcp with vlan_id sometimes. if 'vlan_id' in match_map and not 'vlan_pcp' in match_map: match_map['vlan_pcp'] = 0 # Add auxiliary information for VLAN matches if 'vlan_id' in match_map: match_map['vlan_offset'] = vlan_offset_nbits['vlan_offset'] match_map['vlan_nbits'] = vlan_offset_nbits['vlan_nbits'] match_map['vlan_total_stages'] = vlan_offset_nbits['vlan_total_stages'] # Ensure both id and pcp are set by the time we return match. assert (not 'vlan_id' in match_map) or 'vlan_pcp' in match_map assert (not 'vlan_pcp' in match_map) or 'vlan_id' in match_map return match(**match_map)
def track_eval(self, pkt, dry): """Don't look any more such packets""" eval_trace = EvalTrace(self) (results, trace) = self.policy.track_eval(pkt, dry) eval_trace.add_trace(trace) if results: if not dry: (results, trace) = self.pwfb.track_eval(pkt, dry) eval_trace.add_trace(trace) if not results: val = {h: pkt[h] for h in self.group_by} self.policy = ~match(val) & self.policy else: eval_trace.add_trace(EvalTrace(self.pwfb)) return (set(), eval_trace)
def track_eval(self,pkt,dry): """Don't look any more such packets""" eval_trace = EvalTrace(self) (results,trace) = self.policy.track_eval(pkt,dry) eval_trace.add_trace(trace) if results: if not dry: (results,trace) = self.pwfb.track_eval(pkt,dry) eval_trace.add_trace(trace) if not results: val = {h : pkt[h] for h in self.group_by} self.policy = ~match(val) & self.policy else: eval_trace.add_trace(EvalTrace(self.pwfb)) return (set(),eval_trace)
def create_match(pattern, switch_id, vlan_offset_nbits): from pyretic.core.language import match def __reverse_mac__(m): return ':'.join(m.split(':')[::-1]) if switch_id > 0: match_map = {'switch' : switch_id} else: match_map = {} vlan_processed = False for k,v in pattern.items(): if v is not None: if k == 'dlSrc' or k == 'dlDst': """ TODO: NetKat returns MAC addresses reversed. """ match_map[field_map[k]] = MAC(__reverse_mac__(v)) elif k == 'dlVlan' or k == 'dlVlanPcp': """ Reset `None` value for VLAN matches, if any. """ if not vlan_processed: if (('dlVlan' in pattern and pattern['dlVlan'] == VLAN_NONE_VALUE) and ('dlVlanPcp' in pattern and pattern['dlVlanPcp'] == VLAN_PCP_NONE_VALUE)): match_map['vlan_id'] = None match_map['vlan_pcp'] = None else: def get_num(v): # HACK! Sometimes, one of the fields has a value # `None`. TODO: Must understand why this happens, # because the compiler/runtime always set vlan_id # and vlan_pcp together. May well lead to bugs in # future! return v if not v is None else 0 match_map['vlan_id'] = get_num(pattern['dlVlan']) match_map['vlan_pcp'] = get_num(pattern['dlVlanPcp']) vlan_processed = True else: match_map[field_map[k]] = v # HACK! NetKat doesn't return vlan_pcp with vlan_id sometimes. if 'vlan_id' in match_map and not 'vlan_pcp' in match_map: match_map['vlan_pcp'] = 0 # Add auxiliary information for VLAN matches if 'vlan_id' in match_map: match_map['vlan_offset'] = vlan_offset_nbits['vlan_offset'] match_map['vlan_nbits'] = vlan_offset_nbits['vlan_nbits'] match_map['vlan_total_stages'] = vlan_offset_nbits['vlan_total_stages'] # Ensure both id and pcp are set by the time we return match. assert (not 'vlan_id' in match_map) or 'vlan_pcp' in match_map assert (not 'vlan_pcp' in match_map) or 'vlan_id' in match_map return match(**match_map)
def set_network(self, network): changed = False super(flood,self).set_network(network) if not network is None: updated_mst = Topology.minimum_spanning_tree(network.topology) if not self.mst is None: if self.mst != updated_mst: self.mst = updated_mst changed = True else: self.mst = updated_mst changed = True if changed: self.policy = parallel([ match(switch=switch) >> parallel(map(xfwd,attrs['ports'].keys())) for switch,attrs in self.mst.nodes(data=True)])
def set_network(self, network): changed = False super(flood, self).set_network(network) if not network is None: updated_mst = Topology.minimum_spanning_tree(network.topology) if not self.mst is None: if self.mst != updated_mst: self.mst = updated_mst changed = True else: self.mst = updated_mst changed = True if changed: self.policy = parallel([ match(switch=switch) >> parallel( map(xfwd, attrs['ports'].keys())) for switch, attrs in self.mst.nodes(data=True) ])
def __init__(self, time_window, **kwargs): super(visited,self).__init__() loggername = "netassay." + self.__class__.__name__ logging.getLogger(loggername).info("__init__(): called") self.logger = logging.getLogger(loggername) self.naw = NetAssayWindow.get_instance() self.time_window = time_window self.kwargs_filter = match(**kwargs) self.visit_list = [] self.timer = None self.important_pkts = packets(1, ['srcmac', 'dstmac', 'srcip', 'dstip', 'srcport', 'dstport', 'protocol']) self.important_pkts.register_callback(self._pkt_callback) self.registered_rule = self.kwargs_filter >> self.important_pkts self.naw.register_forwarding_rule(self.registered_rule)
def create_match(pattern, switch_id): from pyretic.core.language import match def __reverse_mac__(m): return ':'.join(m.split(':')[::-1]) if switch_id > 0: match_map = {'switch' : switch_id} else: match_map = {} for k,v in pattern.items(): if v is not None: if k == 'dlSrc' or k == 'dlDst': """ TODO: NetKat returns MAC addresses reversed. """ match_map[field_map[k]] = MAC(__reverse_mac__(v)) else: match_map[field_map[k]] = v # HACK! NetKat doesn't return vlan_pcp with vlan_id sometimes. if 'vlan_id' in match_map and not 'vlan_pcp' in match_map: match_map['vlan_pcp'] = 0 return match(**match_map)
def __init__(self, outport): self.outport = outport super(fwd, self).__init__( if_(match(outport=-1), pop('outport')) >> push( outport=self.outport))
def get_pred_from_pkt(self, pkt): if self.group_by: # MATCH ON PROVIDED GROUP_BY return match([(field,pkt[field]) for field in self.group_by]) else: # OTHERWISE, MATCH ON ALL AVAILABLE GROUP_BY return match([(field,pkt[field]) for field in pkt.available_fields()])
def __init__(self, field, group): self.group = group self.field = field super(_in, self).__init__(parallel([match({field: i}) for i in group]))
def __init__(self,field,group): self.group = group self.field = field super(_in,self).__init__(union([match({field : i}) for i in group]))
def eval(self,pkt): """Don't look any more such packets""" if self.policy.eval(pkt) and not self.pwfb.eval(pkt): val = {h : pkt[h] for h in self.group_by} self.policy = ~match(val) & self.policy return set()
def dum_policy(sdx, es): return (match(dstip=IP(dummyhostip), ethtype=ARP_TYPE) >> fwd(5)) + \ (match(inport=5) >> parallel( [match(dstmac=mac) >> fwd(port.id_) for mac, port in sdx.mac_to_port.items()]) ) + (match(dstip=IP(dummyhostip), ethtype=IP_TYPE, protocol=ICMP) >> EchoReciever(es))
def __init__(self, field, match_val, mod_val): self.field = field self.match_val = match_val self.mod_val = mod_val super(match_modify,self).__init__(match(field=match_val) >> modify(field=mod_val))
def make_firewall_policy(config): print config # The rules list contains all of the individual rule entries. rules = [] # Protocol constants from packet. both = (match(protocol=packet.TCP_PROTO, ethtype=packet.IPV4) | match(protocol=packet.UDP_PROTO, ethtype=packet.IPV4)) tcp = match(protocol=packet.TCP_PROTO, ethtype=packet.IPV4) udp = match(protocol=packet.UDP_PROTO, ethtype=packet.IPV4) icmp = match(protocol=packet.ICMP_PROTO, ethtype=packet.IPV4) for entry in config: # The rules_items list contains all of the individual rule items. rule_items = [] for key, value in entry.iteritems(): if key != 'rulenum' and value != '-': if key == 'macaddr_src': rule_items.append(match(srcmac=MAC(value))) elif key == 'macaddr_dst': rule_items.append(match(dstmac=MAC(value))) elif key == 'ipaddr_src': rule_items.append(match(srcip=IPAddr(value))) elif key == 'ipaddr_dst': rule_items.append(match(dstip=IPAddr(value))) elif key == 'port_src': rule_items.append( match(srcport=int(value), ethtype=packet.IPV4)) elif key == 'port_dst': rule_items.append( match(dstport=int(value), ethtype=packet.IPV4)) elif key == 'protocol': if value == 'T': rule_items.append(tcp) elif value == 'U': rule_items.append(udp) elif value == 'I': rule_items.append(icmp) elif value == 'B': rule_items.append(both) elif key == 'ipproto': rule_items.append( match(protocol=int(value), ethtype=packet.IPV4)) # Append only non-empty rules. if len(rule_items) > 0: rule = reduce(lambda x, y: x & y, rule_items) rules.append(rule) pass # Think about the following line. What is it doing? # The line negates all traffic that matches the specified rules. allowed = ~(union(rules)) print allowed return allowed
def __init__(self, outport): self.outport = outport super(xfwd,self).__init__((~match(inport=outport)) >> fwd(outport))
def __init__(self, outport): self.outport = outport super(fwd,self).__init__(if_(match(outport=-1),pop('outport')) >> push(outport=self.outport))
def get_pred_from_pkt(self, pkt): if self.group_by: # MATCH ON PROVIDED GROUP_BY return match([(field, pkt[field]) for field in self.group_by]) else: # OTHERWISE, MATCH ON ALL AVAILABLE GROUP_BY return match([(field, pkt[field]) for field in pkt.available_fields()])
def __init__(self, field, match_val, mod_val): self.field = field self.match_val = match_val self.mod_val = mod_val super(match_modify, self).__init__(match(field=match_val) >> modify(field=mod_val))
def eval(self, pkt): """Don't look any more such packets""" if self.policy.eval(pkt) and not self.pwfb.eval(pkt): val = {h: pkt[h] for h in self.group_by} self.policy = ~match(val) & self.policy return set()
def __init__(self, outport): self.outport = outport super(xfwd, self).__init__((~match(inport=outport)) >> fwd(outport))