From 330462a315795834a06fb1683b7a360c5fef3089 Mon Sep 17 00:00:00 2001 From: Bernd Walter Date: Wed, 4 Jun 2003 01:17:37 +0000 Subject: [PATCH] Change handling to support strong alignment architectures such as alpha and sparc64. PR: alpha/50658 Submitted by: rizzo Tested on: alpha --- sbin/ipfw/ipfw2.c | 46 +++++++++++++++++++++++++++++---------- sys/netinet/ip_dummynet.c | 8 +++++++ sys/netinet/ip_fw.h | 22 ++++++++++++++----- sys/netinet/ip_fw2.c | 21 +++++++++++++----- 4 files changed, 74 insertions(+), 23 deletions(-) diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index edec049e988e..b33fdc065b7e 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -348,6 +348,14 @@ struct _s_x rule_options[] = { { NULL, 0 } }; +static __inline u_int64_t +align_uint64(u_int64_t *pll) { + u_int64_t ret; + + bcopy (pll, &ret, sizeof(ret)); + return ret; +}; + /** * match_token takes a table and a string, returns the value associated * with the string (0 meaning an error in most cases) @@ -813,8 +821,9 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) int flags = 0; /* prerequisites */ ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ int or_block = 0; /* we are in an or block */ + u_int32_t set_disable; - u_int32_t set_disable = rule->set_disable; + bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); if (set_disable & (1 << rule->set)) { /* disabled */ if (!show_sets) @@ -825,8 +834,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) printf("%05u ", rule->rulenum); if (do_acct) - printf("%*llu %*llu ", pcwidth, rule->pcnt, bcwidth, - rule->bcnt); + printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), + bcwidth, align_uint64(&rule->bcnt)); if (do_time) { char timestr[30]; @@ -1213,14 +1222,18 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) { struct protoent *pe; struct in_addr a; + uint16_t rulenum; if (!do_expired) { if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) return; } - printf("%05d %*llu %*llu (%ds)", d->rulenum, pcwidth, d->pcnt, bcwidth, - d->bcnt, d->expire); + bcopy(&d->rule, &rulenum, sizeof(rulenum)); + + printf("%05d %*llu %*llu (%ds)", rulenum, pcwidth, + align_uint64(&d->pcnt), bcwidth, + align_uint64(&d->bcnt), d->expire); switch (d->dyn_type) { case O_LIMIT_PARENT: printf(" PARENT %d", d->count); @@ -1454,7 +1467,9 @@ sets_handler(int ac, char *av[]) err(EX_OSERR, "malloc"); if (getsockopt(s, IPPROTO_IP, IP_FW_GET, data, &nbytes) < 0) err(EX_OSERR, "getsockopt(IP_FW_GET)"); - set_disable = ((struct ip_fw *)data)->set_disable; + bcopy(&((struct ip_fw *)data)->next_rule, + &set_disable, sizeof(set_disable)); + for (i = 0, msg = "disable" ; i < 31; i++) if ( (set_disable & (1<pcnt); + width = snprintf(NULL, 0, "%llu", + align_uint64(&r->pcnt)); if (width > pcwidth) pcwidth = width; /* byte counter */ - width = snprintf(NULL, 0, "%llu", r->bcnt); + width = snprintf(NULL, 0, "%llu", + align_uint64(&r->bcnt)); if (width > bcwidth) bcwidth = width; } } if (do_dynamic && ndyn) { for (n = 0, d = dynrules; n < ndyn; n++, d++) { - width = snprintf(NULL, 0, "%llu", d->pcnt); + width = snprintf(NULL, 0, "%llu", + align_uint64(&d->pcnt)); if (width > pcwidth) pcwidth = width; - width = snprintf(NULL, 0, "%llu", d->bcnt); + width = snprintf(NULL, 0, "%llu", + align_uint64(&d->bcnt)); if (width > bcwidth) bcwidth = width; } @@ -1690,9 +1709,12 @@ list(int ac, char *av[]) /* already warned */ continue; for (n = 0, d = dynrules; n < ndyn; n++, d++) { - if (d->rulenum > rnum) + uint16_t rulenum; + + bcopy(&d->rule, &rulenum, sizeof(rulenum)); + if (rulenum > rnum) break; - if (d->rulenum == rnum) + if (rulenum == rnum) show_dyn_ipfw(d, pcwidth, bcwidth); } } diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index 0ea186892486..78c7b4d4bccd 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -1027,7 +1027,11 @@ locate_flowset(int pipe_nr, struct ip_fw *rule) if (cmd->opcode == O_LOG) cmd += F_LEN(cmd); +#ifdef __i386__ fs = ((ipfw_insn_pipe *)cmd)->pipe_ptr; +#else + bcopy(& ((ipfw_insn_pipe *)cmd)->pipe_ptr, &fs, sizeof(fs)); +#endif if (fs != NULL) return fs; @@ -1049,7 +1053,11 @@ locate_flowset(int pipe_nr, struct ip_fw *rule) } /* record for the future */ #if IPFW2 +#ifdef __i386__ ((ipfw_insn_pipe *)cmd)->pipe_ptr = fs; +#else + bcopy(&fs, & ((ipfw_insn_pipe *)cmd)->pipe_ptr, sizeof(fs)); +#endif #else if (fs != NULL) rule->pipe_ptr = fs; diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index f2b932e39fd5..3aa27999cbf5 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -32,11 +32,16 @@ * The kernel representation of ipfw rules is made of a list of * 'instructions' (for all practical purposes equivalent to BPF * instructions), which specify which fields of the packet - * (or its metatada) should be analysed. + * (or its metadata) should be analysed. * * Each instruction is stored in a structure which begins with * "ipfw_insn", and can contain extra fields depending on the * instruction type (listed below). + * Note that the code is written so that individual instructions + * have a size which is a multiple of 32 bits. This means that, if + * such structures contain pointers or other 64-bit entities, + * (there is just one instance now) they may end up unaligned on + * 64-bit architectures, so the must be handled with care. * * "enum ipfw_opcodes" are the opcodes supported. We can have up * to 256 different opcodes. @@ -211,7 +216,7 @@ typedef struct _ipfw_insn_if { ipfw_insn o; union { struct in_addr ip; - int unit; + int32_t unit; } p; char name[IFNAMSIZ]; } ipfw_insn_if; @@ -220,10 +225,13 @@ typedef struct _ipfw_insn_if { * This is used for pipe and queue actions, which need to store * a single pointer (which can have different size on different * architectures. + * Note that, because of previous instructions, pipe_ptr might + * be unaligned in the overall structure, so it needs to be + * manipulated with care. */ typedef struct _ipfw_insn_pipe { ipfw_insn o; - void *pipe_ptr; + void *pipe_ptr; /* XXX */ } ipfw_insn_pipe; /* @@ -278,7 +286,9 @@ typedef struct _ipfw_insn_log { struct ip_fw { struct ip_fw *next; /* linked list of rules */ struct ip_fw *next_rule; /* ptr to next [skipto] rule */ +#if 0 /* passed up using 'next_rule' */ u_int32_t set_disable; /* disabled sets (for userland) */ +#endif u_int16_t act_ofs; /* offset of action in 32-bit units */ u_int16_t cmd_len; /* # of 32-bit words in cmd */ u_int16_t rulenum; /* rule number */ @@ -319,12 +329,12 @@ typedef struct _ipfw_dyn_rule ipfw_dyn_rule; struct _ipfw_dyn_rule { ipfw_dyn_rule *next; /* linked list of rules. */ - struct ipfw_flow_id id; /* (masked) flow id */ struct ip_fw *rule; /* pointer to rule */ ipfw_dyn_rule *parent; /* pointer to parent rule */ - u_int32_t expire; /* expire time */ u_int64_t pcnt; /* packet match counter */ u_int64_t bcnt; /* byte match counter */ + struct ipfw_flow_id id; /* (masked) flow id */ + u_int32_t expire; /* expire time */ u_int32_t bucket; /* which bucket in hash table */ u_int32_t state; /* state of this rule (typically a * combination of TCP flags) @@ -334,7 +344,9 @@ struct _ipfw_dyn_rule { /* to generate keepalives) */ u_int16_t dyn_type; /* rule type */ u_int16_t count; /* refcount */ +#if 0 /* passed up with 'rule' */ u_int16_t rulenum; /* rule number (for userland) */ +#endif }; /* diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 1b7b143a9da8..95a153ed6633 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -2020,8 +2020,15 @@ flush_pipe_ptrs(struct dn_flow_set *match) if (cmd->o.opcode != O_PIPE && cmd->o.opcode != O_QUEUE) continue; - if (match == NULL || cmd->pipe_ptr == match) - cmd->pipe_ptr = NULL; + /* + * XXX Use bcmp/bzero to handle pipe_ptr to overcome + * possible alignment problems on 64-bit architectures. + * This code is seldom used so we do not worry too + * much about efficiency. + */ + if (match == NULL || + !bcmp(&cmd->pipe_ptr, &match, sizeof(match)) ) + bzero(&cmd->pipe_ptr, sizeof(cmd->pipe_ptr)); } } @@ -2562,7 +2569,8 @@ ipfw_ctl(struct sockopt *sopt) for (rule = layer3_chain; rule ; rule = rule->next) { int i = RULESIZE(rule); bcopy(rule, bp, i); - ((struct ip_fw *)bp)->set_disable = set_disable; + bcopy(&set_disable, &(bp->next_rule), + sizeof(set_disable)); bp = (struct ip_fw *)((char *)bp + i); } if (ipfw_dyn_v) { @@ -2574,21 +2582,22 @@ ipfw_ctl(struct sockopt *sopt) for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) { bcopy(p, dst, sizeof *p); - dst->rulenum = p->rule->rulenum; + bcopy(&(p->rule->rulenum), &(dst->rule), + sizeof(p->rule->rulenum)); /* * store a non-null value in "next". * The userland code will interpret a * NULL here as a marker * for the last dynamic rule. */ - dst->next = dst ; + bcopy(&dst, &dst->next, sizeof(dst)); last = dst ; dst->expire = TIME_LEQ(dst->expire, time_second) ? 0 : dst->expire - time_second ; } if (last != NULL) /* mark last dynamic rule */ - last->next = NULL; + bzero(&last->next, sizeof(last)); } splx(s);