Conversation
we ensure that layer 2 rules are inserted in layer 2 groups and layer 3 rules in layer 3 groups
here, rules are moved up to kernel and only l2 flagged bytcode are executed by layer2 handler and l3 flagged byte code are executed by l3 handler for l2, we use per interface filter hooks, we traverse all the interfaces on the system and hook our function with the ifnet pointer as key in the hook head we see a lot of duplications here: the decision to leave code in the different layer duplicated reduces a lot of branching and also personal decision to keep them as decoupled as possible.
and also add ether pass and ether block stats in npfctl stat
| * including the interface the frame is traveling on | ||
| */ | ||
| nbuf_init(npf, &nbuf, *mp, ifp); | ||
| memset(&npc, 0, sizeof(npf_cache_t)); |
|
|
||
| if (npf_ph_ether) { | ||
| error = pfil_add_hook(npfos_layer2_handler, npf, | ||
| PFIL_ALL, npf_ph_ether); |
| register_etherpfil_hook(npf_t *npf, ifnet_t *ifp, int i) | ||
| { | ||
| int error = 0; | ||
| static pfil_head_t * npf_ph_ether; |
| destroy_pfilether_hook(npf_t *npf) | ||
| { | ||
| int i = 0; | ||
| while(npf_ph_etherlist[i]) { |
| { | ||
| int i = 0; | ||
| while(npf_ph_etherlist[i]) { | ||
| pfil_head_t *npf_ph_ether; |
There was a problem hiding this comment.
why not assign in the decl?
| } | ||
|
|
||
| } else if (type && type != ctx->eth_type) { | ||
| errx(EXIT_FAILURE, "ether type mismatch"); |
There was a problem hiding this comment.
print the types that did not match
| const uint32_t *awords = (const uint32_t *)ether_addr; | ||
|
|
||
| off = (opts & MATCH_SRC) ? offsetof(struct ether_header, ether_shost) : | ||
| offsetof(struct ether_header, ether_dhost); |
| { | ||
| unsigned off; | ||
| assert(((opts & MATCH_SRC) != 0) ^ ((opts & MATCH_DST) != 0)); | ||
| const uint32_t *awords = (const uint32_t *)ether_addr; |
There was a problem hiding this comment.
How do you know that this is aligned properly?
| bc = npfctl_bpf_create(); | ||
| if (fopts->layer == NPF_RULE_LAYER_3) { | ||
| if (!build_l3_code(bc, rl, family, popts, fopts)) | ||
| return false; |
| static uint32_t | ||
| npf_rule_layer_compat(nl_rule_t *cg, uint32_t layer) | ||
| { | ||
| const char *str = (layer & NPF_RULE_LAYER_2) ? "layer 2" : "layer 3"; |
There was a problem hiding this comment.
You are using 2 flags one for layer 2 and one for layer 3, then you test layer 2 here and in the code above you test layer 3 (with the else being the other one). Why do you need two flags? Are we planning to filter more layers in the future? And if we do, then if-then-else is not good enough.
|
|
||
| if ((attr & layer) == 0) { | ||
| yyerror("cannot insert %s rules in this group" | ||
| " make sure to insert same layer rules in same group ", str); |
| memset(&imfopts, 0, sizeof(filt_opts_t)); | ||
| memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t)); | ||
| imfopts.layer = NPF_RULE_LAYER_3; | ||
| memcpy(&imfopts.filt.opt3.fo_from, ap1, sizeof(addr_port_t)); |
|
|
||
| while (*cp) { | ||
| if (!isxdigit(*cp)) | ||
| yyerror("%s", err); |
There was a problem hiding this comment.
Print the address that is bad too.
| if (*cp == '\0') | ||
| return; | ||
| else | ||
| yyerror("%s", err); |
There was a problem hiding this comment.
be more specific in the error.
| } | ||
|
|
||
| switch (*cp) { | ||
| case ':': |
|
|
||
| _DIAGASSERT(type != NULL); | ||
|
|
||
| easprintf(&a, "%c%c%02x%02x", 'E', 'x', type[0], type[1]); |
| void | ||
| fetch_ether_type(npf_bpf_t *ctx, uint16_t type) | ||
| { | ||
| if ((ctx->flags & FETCHED_L2) == 0 || (type && ctx->eth_type == 0)) { |
There was a problem hiding this comment.
early returns, reverse the if logic and return early so you can unindent the code.
| static nl_rule_t * | ||
| set_defgroup(nl_rule_t *rl, nl_rule_t *def_group, int attr) | ||
| { | ||
| const char *str = (attr & NPF_RULE_LAYER_3) ? "layer 3" : "layer 2"; |
There was a problem hiding this comment.
not used by the other error so why always compute it?
There was a problem hiding this comment.
also you have code figuring out the layer string again below, centralize it to a method.
| if ((attr & layer) == 0) { | ||
| /* only set the layer strings when you need them */ | ||
| const char *str; | ||
| if (layer & NPF_RULE_LAYER_2) |
| memset(&imfopts, 0, sizeof(filt_opts_t)); | ||
| memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t)); | ||
| imfopts.layer = NPF_RULE_LAYER_3; | ||
| memcpy(&imfopts.filt.opt3.fo_from, ap1, sizeof(addr_port_t)); |
|
|
||
| filt_opts_t | ||
| npfctl_parse_l3filt_opt(npfvar_t *src_addr, npfvar_t *src_port, bool tnot, | ||
| npfvar_t *dst_addr, npfvar_t *dst_port, bool fnot) |
|
|
||
| filt_opts_t | ||
| npfctl_parse_l2filt_opt(npfvar_t *src_addr, bool fnot, npfvar_t *dst_addr, | ||
| bool tnot, uint16_t eth_type) |
| enum { /* book marks for L2 */ | ||
| BM_ETHER_TYPE, BM_SRC_ETHER, BM_DST_ETHER, BM_SRC_ENEG, BM_DST_ENEG, | ||
|
|
||
| //BML2_COUNT // total number of l2 marks |
|
|
||
| off = (opts & MATCH_SRC) ? offsetof(struct ether_header, ether_shost) : | ||
| offsetof(struct ether_header, ether_dhost); | ||
| const uint32_t word_offset = sizeof(uint32_t); |
There was a problem hiding this comment.
forget about word_offset and use sizeof(mac_word) like we do in the memcpy case.
| static nl_rule_t * the_rule = NULL; | ||
| static bool npf_conf_built = false; | ||
|
|
||
| static bool l2_group = false;; |
There was a problem hiding this comment.
I don't like this global, and why ;;?
| static bool npf_conf_built = false; | ||
|
|
||
| static bool l2_group = false;; | ||
| static nl_rule_t * defgroup = NULL; |
There was a problem hiding this comment.
rename to defgroup_l3 for clarity?
sys/dev/usb/xhci.c: revision 1.192 Don't generate duplicate events when sending ZLP. Patch from sc_dying as posted to tech-kern. Addresses PR/59678.
This is work covering the development of media access control filtering in NPF
has been tested on my netbsd using ssh connections and checking the statistics and everything works as expected.
work available and opened for review.
test to be written after completed review.