OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [ipv6/] [fib6_rules.c] - Blame information for rev 81

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * net/ipv6/fib6_rules.c        IPv6 Routing Policy Rules
3
 *
4
 * Copyright (C)2003-2006 Helsinki University of Technology
5
 * Copyright (C)2003-2006 USAGI/WIDE Project
6
 *
7
 *      This program is free software; you can redistribute it and/or
8
 *      modify it under the terms of the GNU General Public License as
9
 *      published by the Free Software Foundation, version 2.
10
 *
11
 * Authors
12
 *      Thomas Graf             <tgraf@suug.ch>
13
 *      Ville Nuorvala          <vnuorval@tcs.hut.fi>
14
 */
15
 
16
#include <linux/netdevice.h>
17
 
18
#include <net/fib_rules.h>
19
#include <net/ipv6.h>
20
#include <net/addrconf.h>
21
#include <net/ip6_route.h>
22
#include <net/netlink.h>
23
 
24
struct fib6_rule
25
{
26
        struct fib_rule         common;
27
        struct rt6key           src;
28
        struct rt6key           dst;
29
        u8                      tclass;
30
};
31
 
32
static struct fib_rules_ops fib6_rules_ops;
33
 
34
struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
35
                                   pol_lookup_t lookup)
36
{
37
        struct fib_lookup_arg arg = {
38
                .lookup_ptr = lookup,
39
        };
40
 
41
        fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg);
42
        if (arg.rule)
43
                fib_rule_put(arg.rule);
44
 
45
        if (arg.result)
46
                return arg.result;
47
 
48
        dst_hold(&ip6_null_entry.u.dst);
49
        return &ip6_null_entry.u.dst;
50
}
51
 
52
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
53
                            int flags, struct fib_lookup_arg *arg)
54
{
55
        struct rt6_info *rt = NULL;
56
        struct fib6_table *table;
57
        pol_lookup_t lookup = arg->lookup_ptr;
58
 
59
        switch (rule->action) {
60
        case FR_ACT_TO_TBL:
61
                break;
62
        case FR_ACT_UNREACHABLE:
63
                rt = &ip6_null_entry;
64
                goto discard_pkt;
65
        default:
66
        case FR_ACT_BLACKHOLE:
67
                rt = &ip6_blk_hole_entry;
68
                goto discard_pkt;
69
        case FR_ACT_PROHIBIT:
70
                rt = &ip6_prohibit_entry;
71
                goto discard_pkt;
72
        }
73
 
74
        table = fib6_get_table(rule->table);
75
        if (table)
76
                rt = lookup(table, flp, flags);
77
 
78
        if (rt != &ip6_null_entry) {
79
                struct fib6_rule *r = (struct fib6_rule *)rule;
80
 
81
                /*
82
                 * If we need to find a source address for this traffic,
83
                 * we check the result if it meets requirement of the rule.
84
                 */
85
                if ((rule->flags & FIB_RULE_FIND_SADDR) &&
86
                    r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
87
                        struct in6_addr saddr;
88
                        if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst,
89
                                           &saddr))
90
                                goto again;
91
                        if (!ipv6_prefix_equal(&saddr, &r->src.addr,
92
                                               r->src.plen))
93
                                goto again;
94
                        ipv6_addr_copy(&flp->fl6_src, &saddr);
95
                }
96
                goto out;
97
        }
98
again:
99
        dst_release(&rt->u.dst);
100
        rt = NULL;
101
        goto out;
102
 
103
discard_pkt:
104
        dst_hold(&rt->u.dst);
105
out:
106
        arg->result = rt;
107
        return rt == NULL ? -EAGAIN : 0;
108
}
109
 
110
 
111
static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
112
{
113
        struct fib6_rule *r = (struct fib6_rule *) rule;
114
 
115
        if (r->dst.plen &&
116
            !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
117
                return 0;
118
 
119
        /*
120
         * If FIB_RULE_FIND_SADDR is set and we do not have a
121
         * source address for the traffic, we defer check for
122
         * source address.
123
         */
124
        if (r->src.plen) {
125
                if (flags & RT6_LOOKUP_F_HAS_SADDR) {
126
                        if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr,
127
                                               r->src.plen))
128
                                return 0;
129
                } else if (!(r->common.flags & FIB_RULE_FIND_SADDR))
130
                        return 0;
131
        }
132
 
133
        if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
134
                return 0;
135
 
136
        return 1;
137
}
138
 
139
static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = {
140
        FRA_GENERIC_POLICY,
141
};
142
 
143
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
144
                               struct nlmsghdr *nlh, struct fib_rule_hdr *frh,
145
                               struct nlattr **tb)
146
{
147
        int err = -EINVAL;
148
        struct fib6_rule *rule6 = (struct fib6_rule *) rule;
149
 
150
        if (rule->action == FR_ACT_TO_TBL) {
151
                if (rule->table == RT6_TABLE_UNSPEC)
152
                        goto errout;
153
 
154
                if (fib6_new_table(rule->table) == NULL) {
155
                        err = -ENOBUFS;
156
                        goto errout;
157
                }
158
        }
159
 
160
        if (frh->src_len)
161
                nla_memcpy(&rule6->src.addr, tb[FRA_SRC],
162
                           sizeof(struct in6_addr));
163
 
164
        if (frh->dst_len)
165
                nla_memcpy(&rule6->dst.addr, tb[FRA_DST],
166
                           sizeof(struct in6_addr));
167
 
168
        rule6->src.plen = frh->src_len;
169
        rule6->dst.plen = frh->dst_len;
170
        rule6->tclass = frh->tos;
171
 
172
        err = 0;
173
errout:
174
        return err;
175
}
176
 
177
static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
178
                             struct nlattr **tb)
179
{
180
        struct fib6_rule *rule6 = (struct fib6_rule *) rule;
181
 
182
        if (frh->src_len && (rule6->src.plen != frh->src_len))
183
                return 0;
184
 
185
        if (frh->dst_len && (rule6->dst.plen != frh->dst_len))
186
                return 0;
187
 
188
        if (frh->tos && (rule6->tclass != frh->tos))
189
                return 0;
190
 
191
        if (frh->src_len &&
192
            nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
193
                return 0;
194
 
195
        if (frh->dst_len &&
196
            nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
197
                return 0;
198
 
199
        return 1;
200
}
201
 
202
static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
203
                          struct nlmsghdr *nlh, struct fib_rule_hdr *frh)
204
{
205
        struct fib6_rule *rule6 = (struct fib6_rule *) rule;
206
 
207
        frh->family = AF_INET6;
208
        frh->dst_len = rule6->dst.plen;
209
        frh->src_len = rule6->src.plen;
210
        frh->tos = rule6->tclass;
211
 
212
        if (rule6->dst.plen)
213
                NLA_PUT(skb, FRA_DST, sizeof(struct in6_addr),
214
                        &rule6->dst.addr);
215
 
216
        if (rule6->src.plen)
217
                NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr),
218
                        &rule6->src.addr);
219
 
220
        return 0;
221
 
222
nla_put_failure:
223
        return -ENOBUFS;
224
}
225
 
226
static u32 fib6_rule_default_pref(void)
227
{
228
        return 0x3FFF;
229
}
230
 
231
static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
232
{
233
        return nla_total_size(16) /* dst */
234
               + nla_total_size(16); /* src */
235
}
236
 
237
static struct fib_rules_ops fib6_rules_ops = {
238
        .family                 = AF_INET6,
239
        .rule_size              = sizeof(struct fib6_rule),
240
        .addr_size              = sizeof(struct in6_addr),
241
        .action                 = fib6_rule_action,
242
        .match                  = fib6_rule_match,
243
        .configure              = fib6_rule_configure,
244
        .compare                = fib6_rule_compare,
245
        .fill                   = fib6_rule_fill,
246
        .default_pref           = fib6_rule_default_pref,
247
        .nlmsg_payload          = fib6_rule_nlmsg_payload,
248
        .nlgroup                = RTNLGRP_IPV6_RULE,
249
        .policy                 = fib6_rule_policy,
250
        .rules_list             = LIST_HEAD_INIT(fib6_rules_ops.rules_list),
251
        .owner                  = THIS_MODULE,
252
};
253
 
254
static int __init fib6_default_rules_init(void)
255
{
256
        int err;
257
 
258
        err = fib_default_rule_add(&fib6_rules_ops, 0,
259
                                   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
260
        if (err < 0)
261
                return err;
262
        err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
263
        if (err < 0)
264
                return err;
265
        return 0;
266
}
267
 
268
void __init fib6_rules_init(void)
269
{
270
        BUG_ON(fib6_default_rules_init());
271
        fib_rules_register(&fib6_rules_ops);
272
}
273
 
274
void fib6_rules_cleanup(void)
275
{
276
        fib_rules_unregister(&fib6_rules_ops);
277
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.