From 24ac09fbda71ebca5ec7b668a110613124d08558 Mon Sep 17 00:00:00 2001 From: duxbbo Date: Mon, 25 Jul 2022 07:09:57 +0000 Subject: [PATCH] add route Signed-off-by: duxbbo --- code/linux/LICENSE | 359 +++++++++++++ code/linux/net/newip/route.c | 959 +++++++++++++++++++++++++++++++++++ 2 files changed, 1318 insertions(+) create mode 100644 code/linux/LICENSE create mode 100644 code/linux/net/newip/route.c diff --git a/code/linux/LICENSE b/code/linux/LICENSE new file mode 100644 index 0000000..ff0812f --- /dev/null +++ b/code/linux/LICENSE @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/code/linux/net/newip/route.c b/code/linux/net/newip/route.c new file mode 100644 index 0000000..dc926ca --- /dev/null +++ b/code/linux/net/newip/route.c @@ -0,0 +1,959 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * ROUTE - implementation of the NewIP router. + * + * Based on net/ipv4/route.c + * Based on net/ipv6/route.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /*copy_from_user()*/ +#include /*rtnl_lock()*/ + +#include +#include +#include +#include +#include + +#include +#include "nip_hdr.h" + +static int nip_pkt_discard(struct sk_buff *skb); +static int nip_pkt_discard_out(struct net *net, struct sock *sk, + struct sk_buff *skb); +static unsigned int nip_mtu(const struct dst_entry *dst); + +static const struct nip_rt_info nip_null_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), + .__use = 1, + .obsolete = DST_OBSOLETE_FORCE_CHK, + .error = -ENETUNREACH, + .input = nip_pkt_discard, + .output = nip_pkt_discard_out, + }, + .rt_ref = ATOMIC_INIT(1), +}; + +static const struct nip_rt_info nip_broadcast_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), + .__use = 1, + .obsolete = DST_OBSOLETE_FORCE_CHK, + .input = nip_input, + .output = nip_output, + }, + .rt_ref = ATOMIC_INIT(1), +}; + +struct nip_addr *nip_nexthop(struct nip_rt_info *rt, struct nip_addr *daddr) +{ + if (rt->rt_flags & RTF_GATEWAY) + return &rt->gateway; + else + return daddr; +} + +static void rtmsg_to_fibni_config(struct net *net, struct nip_rtmsg *rtmsg, + struct nip_fib_config *cfg) +{ + memset(cfg, 0, sizeof(*cfg)); + + cfg->fc_table = NIP_RT_TABLE_MAIN; + cfg->fc_ifindex = rtmsg->rtmsg_ifindex; + cfg->fc_metric = rtmsg->rtmsg_metric; + cfg->fc_expires = rtmsg->rtmsg_info; + + cfg->fc_flags = rtmsg->rtmsg_flags; + + cfg->fc_nlinfo.nl_net = net; + + cfg->fc_dst = rtmsg->rtmsg_dst; + cfg->fc_src = rtmsg->rtmsg_src; + cfg->fc_gateway = rtmsg->rtmsg_gateway; +} + +static void nip_rt_info_init(struct nip_rt_info *rt) +{ + struct dst_entry *dst = &rt->dst; + + memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); + rt->from = NULL; +} + +static struct nip_rt_info *__nip_dst_alloc(struct net *net, + struct net_device *dev, int flags) +{ + struct nip_rt_info *rt = + dst_alloc(&net->newip.nip_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK, + flags); + + if (rt) + nip_rt_info_init(rt); + + return rt; +} + +struct nip_rt_info *nip_dst_alloc(struct net *net, struct net_device *dev, + int flags) +{ + struct nip_rt_info *rt = __nip_dst_alloc(net, dev, flags); + + if (rt) { + rt->rt_pcpu = + alloc_percpu_gfp(struct nip_rt_info *, GFP_ATOMIC); + if (rt->rt_pcpu) { + int cpu; + + for_each_possible_cpu(cpu) { + struct nip_rt_info **p; + + p = per_cpu_ptr(rt->rt_pcpu, cpu); + /* no one shares rt */ + *p = NULL; + } + } else { + dst_destroy((struct dst_entry *)rt); + return NULL; + } + } + + return rt; +} + +static void nip_rt_dst_from_metrics_check(struct nip_rt_info *rt) +{ + if (rt->from && + dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->from)) + dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->from), true); +} + +static struct nip_rt_info *nip_rt_get_pcpu_route(struct nip_rt_info *rt) +{ + struct nip_rt_info *pcpu_rt, **p; + + p = this_cpu_ptr(rt->rt_pcpu); + pcpu_rt = *p; + + if (pcpu_rt) { + dst_hold(&pcpu_rt->dst); + nip_rt_dst_from_metrics_check(pcpu_rt); + } + return pcpu_rt; +} + +static void nip_rt_set_from(struct nip_rt_info *rt, struct nip_rt_info *from) +{ + WARN_ON(from->from); + + rt->rt_flags &= ~RTF_EXPIRES; + dst_hold(&from->dst); + rt->from = &from->dst; + dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); +} + +static void nip_rt_copy_init(struct nip_rt_info *rt, struct nip_rt_info *ort) +{ + rt->dst.input = ort->dst.input; + rt->dst.output = ort->dst.output; + rt->rt_dst = ort->rt_dst; + rt->dst.error = ort->dst.error; + rt->rt_idev = ort->rt_idev; + if (rt->rt_idev) + nin_dev_hold(rt->rt_idev); + + rt->dst.lastuse = jiffies; + rt->gateway = ort->gateway; + rt->rt_flags = ort->rt_flags; + nip_rt_set_from(rt, ort); + rt->rt_metric = ort->rt_metric; + rt->rt_table = ort->rt_table; + rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate); +} + +static struct nip_rt_info *nip_rt_pcpu_alloc(struct nip_rt_info *rt) +{ + struct nip_rt_info *pcpu_rt; + + pcpu_rt = __nip_dst_alloc(dev_net(rt->dst.dev), + rt->dst.dev, rt->dst.flags); + if (!pcpu_rt) + return NULL; + nip_rt_copy_init(pcpu_rt, rt); + pcpu_rt->rt_protocol = rt->rt_protocol; + pcpu_rt->rt_flags |= RTF_PCPU; + return pcpu_rt; +} + +static struct nip_rt_info *nip_rt_make_pcpu_route(struct nip_rt_info *rt) +{ + struct nip_rt_info *pcpu_rt, *prev, **p; + + pcpu_rt = nip_rt_pcpu_alloc(rt); + if (!pcpu_rt) { + struct net *net = dev_net(rt->dst.dev); + + dst_hold(&net->newip.nip_null_entry->dst); + return net->newip.nip_null_entry; + } + + rcu_read_lock_bh(); + if (rt->rt_pcpu) { + p = this_cpu_ptr(rt->rt_pcpu); + prev = cmpxchg(p, NULL, pcpu_rt); + if (prev) { + /* If someone did it before us, return prev instead */ + dst_destroy(&pcpu_rt->dst); + pcpu_rt = prev; + } + } else { + dst_destroy(&pcpu_rt->dst); + pcpu_rt = rt; + } + dst_hold(&pcpu_rt->dst); + nip_rt_dst_from_metrics_check(pcpu_rt); + rcu_read_unlock_bh(); + return pcpu_rt; +} + +static struct nip_rt_info *nip_pol_route_input(struct net *net, + struct nip_fib_table *table, + struct flow_nip *fln, int flags) +{ + return nip_pol_route(net, table, fln->flowin_iif, fln, flags); +} + +struct dst_entry *nip_route_input_lookup(struct net *net, + struct net_device *dev, + struct flow_nip *fln, int flags) +{ + return nip_fib_rule_lookup(net, fln, flags, nip_pol_route_input); +} + +void nip_route_input(struct sk_buff *skb) +{ + struct net *net = dev_net(skb->dev); + int flags = 0; + struct flow_nip fln = { + .flowin_iif = skb->skb_iif, + .daddr = NIPCB(skb)->dstaddr, + .saddr = NIPCB(skb)->srcaddr, + }; + + if (nip_addr_eq(&fln.daddr, &nip_broadcast_addr_arp)) { + DEBUG("%s: recv broadcast packet!\n", __func__); + dst_hold(&net->newip.nip_broadcast_entry->dst); + skb_dst_set(skb, + (struct dst_entry *)net->newip.nip_broadcast_entry); + return; + } + + skb_dst_set(skb, nip_route_input_lookup(net, skb->dev, &fln, flags)); +} + +static struct nip_rt_info *nip_pol_route_output(struct net *net, + struct nip_fib_table *table, + struct flow_nip *fln, int flags) +{ + return nip_pol_route(net, table, fln->flowin_oif, fln, flags); +} + +struct dst_entry *nip_route_output_flags(struct net *net, const struct sock *sk, + struct flow_nip *fln, int flags) +{ + struct dst_entry *dst; + struct nip_rt_info *rt; + + dst = nip_fib_rule_lookup(net, fln, flags, nip_pol_route_output); + rt = (struct nip_rt_info *)dst; + + if (rt->rt_flags & RTF_LOCAL) { + rcu_read_lock(); + if (rt->rt_idev) { + read_lock_bh(&rt->rt_idev->lock); + /* search saddr in idev->addr */ + if (!list_empty(&rt->rt_idev->addr_list)) { + struct ninet_ifaddr *ifp; + + list_for_each_entry(ifp, &rt->rt_idev->addr_list, if_list) { + fln->saddr = ifp->addr; + break; + } + } + read_unlock_bh(&rt->rt_idev->lock); + } + rcu_read_unlock(); + + dst_release(dst); + dst_hold(&net->newip.nip_broadcast_entry->dst); + return &net->newip.nip_broadcast_entry->dst; + } + + return dst; +} + +struct nip_rt_info *nip_pol_route(struct net *net, struct nip_fib_table *table, + int oif, struct flow_nip *fln, int flags) +{ + struct nip_fib_node *fn; + struct nip_rt_info *rt, *pcpu_rt; + + rcu_read_lock_bh(); + fn = nip_fib_locate(table->nip_tb_head, &fln->daddr); + if (!fn) { + rcu_read_unlock_bh(); + DEBUG("%s: search fail!\n", __func__); + rt = net->newip.nip_null_entry; + dst_hold_and_use(&rt->dst, jiffies); + return rt; + } + rt = fn->nip_route_info; + + /* Get a percpu copy */ + rt->dst.lastuse = jiffies; + rt->dst.__use++; + pcpu_rt = nip_rt_get_pcpu_route(rt); + + DEBUG("%s: cpu id = %d\n", __func__, smp_processor_id()); + + if (pcpu_rt) { + rcu_read_unlock_bh(); + DEBUG("%s: pcpu found!\n", __func__); + } else { + dst_hold(&rt->dst); + rcu_read_unlock_bh(); + pcpu_rt = nip_rt_make_pcpu_route(rt); + dst_release(&rt->dst); + } + + DEBUG("%s: rt dst.__refcnt = %d ; pcpu dst.__refcnt = %d\n", __func__, + atomic_read(&rt->dst.__refcnt), + atomic_read(&pcpu_rt->dst.__refcnt)); + return pcpu_rt; +} + +bool nip_bind_addr_check(struct net *net, + struct nip_addr *addr) +{ + struct nip_fib_node *fn; + struct nip_fib_table *fib_tbl = net->newip.nip_fib_local_tbl; + + if (nip_addr_invalid(addr)) { + DEBUG("%s: binding-addr invalid.", __func__); + return false; + } + + if (nip_addr_eq(addr, &nip_any_addr)) { + DEBUG("%s: binding-addr is any addr.", __func__); + return true; + } + + rcu_read_lock_bh(); + fn = nip_fib_locate(fib_tbl->nip_tb_head, addr); + rcu_read_unlock_bh(); + if (!fn) { + DEBUG("%s: binding-addr is not local addr.", __func__); + return false; + } + + DEBUG("%s: binding-addr is local addr.", __func__); + return true; +} + +static struct nip_rt_info *nip_route_info_create(struct nip_fib_config *cfg) +{ + struct net *net = cfg->fc_nlinfo.nl_net; + struct nip_rt_info *rt = NULL; + struct net_device *dev = NULL; + struct ninet_dev *idev = NULL; + struct nip_fib_table *table; + int err = -ENODEV; + + /* find net_device */ + dev = dev_get_by_index(net, cfg->fc_ifindex); + if (!dev) { + DEBUG("%s: fail to get dev by ifindex(%u).", __func__, cfg->fc_ifindex); + goto out; + } + + /* find ninet_dev,which has the newip address list */ + idev = nin_dev_get(dev); + if (!idev) { + DEBUG("%s: fail to get ninet dev.(ifindex=%u)", __func__, cfg->fc_ifindex); + goto out; + } + + if (cfg->fc_metric == 0) + cfg->fc_metric = NIP_RT_PRIO_USER; + + err = -ENOBUFS; + table = nip_fib_get_table(net, cfg->fc_table); + if (!table) { + DEBUG("%s: fail to get fib table.(fc_table=%u)", __func__, cfg->fc_table); + goto out; + } + + rt = nip_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT); + if (!rt) { + DEBUG("%s: fail to alloc dst mem.", __func__); + err = -ENOMEM; + goto out; + } + + nip_rt_clean_expires(rt); + + if (cfg->fc_protocol == RTPROT_UNSPEC) + cfg->fc_protocol = RTPROT_BOOT; + rt->rt_protocol = cfg->fc_protocol; + + if (cfg->fc_flags & RTF_LOCAL) { + rt->dst.input = nip_input; + DEBUG("rt->dst.input = nip_input, ifindex=%u", cfg->fc_ifindex); + } else { + rt->dst.input = nip_forward; + DEBUG("rt->dst.input = nip_forward, ifindex=%u", cfg->fc_ifindex); + } + + rt->dst.output = nip_output; + rt->rt_dst = cfg->fc_dst; + rt->rt_src = cfg->fc_src; + rt->rt_metric = cfg->fc_metric; + + if (cfg->fc_flags & RTF_GATEWAY) + rt->gateway = cfg->fc_gateway; + else + rt->gateway = nip_any_addr; + + rt->rt_flags = cfg->fc_flags; + rt->dst.dev = dev; + rt->rt_idev = idev; + rt->rt_table = table; + + return rt; +out: + if (dev) + dev_put(dev); + if (idev) + nin_dev_put(idev); + return ERR_PTR(err); +} + +/* __nip_ins_rt is called with FREE table->nip_tb_lock. + * It takes new route entry, the addition fails by any reason the + * route is released. + */ +static int __nip_ins_rt(struct nip_rt_info *rt) +{ + int err; + struct nip_fib_table *table; + + table = rt->rt_table; + + spin_lock_bh(&table->nip_tb_lock); + err = nip_fib_add(table->nip_tb_head, rt); + spin_unlock_bh(&table->nip_tb_lock); + + return err; +} + +int nip_ins_rt(struct nip_rt_info *rt) +{ + /* Hold dst to account for the reference from the nip fib hash */ + dst_hold(&rt->dst); + return __nip_ins_rt(rt); +} + +int nip_route_add(struct nip_fib_config *cfg) +{ + struct nip_rt_info *rt; + int err; + + rt = nip_route_info_create(cfg); + if (IS_ERR(rt)) { + DEBUG("%s: fail to creat route info.", __func__); + err = PTR_ERR(rt); + rt = NULL; + goto out; + } + + err = __nip_ins_rt(rt); +out: + return err; +} + +static int __nip_del_rt(struct nip_rt_info *rt, struct nl_info *info) +{ + int err; + struct nip_fib_table *table; + struct net *net = dev_net(rt->dst.dev); + + if (rt == net->newip.nip_null_entry) { + err = -ENOENT; + goto out; + } + + table = rt->rt_table; + spin_lock_bh(&table->nip_tb_lock); + err = nip_fib_del(rt, info); + spin_unlock_bh(&table->nip_tb_lock); + +out: + nip_rt_put(rt); + return err; +} + +int nip_del_rt(struct nip_rt_info *rt) +{ + struct nl_info info = { + .nl_net = dev_net(rt->dst.dev), + }; + return __nip_del_rt(rt, &info); +} + +static int nip_route_del(struct nip_fib_config *cfg) +{ + struct net *net = cfg->fc_nlinfo.nl_net; + struct nip_fib_table *table; + struct nip_fib_node *fn; + struct nip_rt_info *rt; + int err = -ESRCH; + + table = nip_fib_get_table(net, cfg->fc_table); + if (!table) + return err; + + rcu_read_lock_bh(); + fn = nip_fib_locate(table->nip_tb_head, &cfg->fc_dst); + if (fn) { + rt = fn->nip_route_info; + dst_hold(&rt->dst); + rcu_read_unlock_bh(); + + return __nip_del_rt(rt, &cfg->fc_nlinfo); + } + rcu_read_unlock_bh(); + + return err; +} + +int nip_route_ioctl(struct net *net, unsigned int cmd, struct nip_rtmsg *rtmsg) +{ + struct nip_fib_config cfg; + int err; + + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { + DEBUG("%s: not admin can`t cfg.", __func__); + return -EPERM; + } + + rtmsg_to_fibni_config(net, rtmsg, &cfg); + if (nip_addr_invalid(&cfg.fc_dst)) { + DEBUG("%s: nip daddr invalid.", __func__); + return -EFAULT; + } + + if (cfg.fc_flags & RTF_GATEWAY) { + if (nip_addr_invalid(&cfg.fc_gateway)) { + DEBUG("%s: nip gateway daddr invalid.", __func__); + return -EFAULT; + } + } + + rtnl_lock(); + switch (cmd) { + case SIOCADDRT: /* Add a route */ + err = nip_route_add(&cfg); + break; + case SIOCDELRT: /* Delete a route */ + err = nip_route_del(&cfg); + break; + default: + err = -EINVAL; + } + rtnl_unlock(); + + return err; +} + +static void nip_dst_destroy(struct dst_entry *dst) +{ + struct nip_rt_info *rt = (struct nip_rt_info *)dst; + struct dst_entry *from = rt->from; + struct ninet_dev *idev; + + dst_destroy_metrics_generic(dst); + free_percpu(rt->rt_pcpu); + + idev = rt->rt_idev; + if (idev) { + rt->rt_idev = NULL; + DEBUG("%s: idev->refcnt=%u\n", __func__, + refcount_read(&idev->refcnt)); + nin_dev_put(idev); + } + + if (from) { + DEBUG("%s: from->__refcnt = %d\n", __func__, + atomic_read(&from->__refcnt)); + } + rt->from = NULL; + dst_release(from); +} + +static inline const void *nip_choose_neigh_daddr(struct nip_rt_info *rt, + struct sk_buff *skb, + const void *daddr) +{ + struct nip_addr *p = &rt->gateway; + + if (rt->rt_flags & RTF_GATEWAY) + return (const void *)p; + else if (skb) + return &NIPCB(skb)->dstaddr; + return daddr; +} + +static struct neighbour *nip_neigh_lookup(const struct dst_entry *dst, + struct sk_buff *skb, + const void *daddr) +{ + struct nip_rt_info *rt = (struct nip_rt_info *)dst; + struct neighbour *n; + + daddr = nip_choose_neigh_daddr(rt, skb, daddr); + n = __nip_neigh_lookup(dst->dev, daddr); + if (n) + return n; + return neigh_create(&nnd_tbl, daddr, dst->dev); +} + +static struct dst_entry *nip_dst_check(struct dst_entry *dst, u32 cookie) +{ + return dst; +} + +/* Used to calculate the MSS value required by TCP + * Because there is no MSS in the TCP of NewIP, + * the value is calculated based on the MTU of the network port + */ +static unsigned int nip_default_advmss(const struct dst_entry *dst) +{ + unsigned int mtu = dst_mtu(dst); + + mtu -= NIP_HDR_MAX + sizeof(struct tcphdr); + + return mtu; +} + +static unsigned int nip_mtu(const struct dst_entry *dst) +{ + unsigned int mtu; + struct ninet_dev *idev; + + mtu = NIP_MIN_MTU; + + rcu_read_lock(); + idev = __nin_dev_get(dst->dev); + if (idev) + mtu = idev->cnf.mtu; + rcu_read_unlock(); + + return mtu; +} + +static struct dst_ops nip_dst_ops_template = { + .family = AF_NINET, + .destroy = nip_dst_destroy, + .neigh_lookup = nip_neigh_lookup, + .check = nip_dst_check, + .default_advmss = nip_default_advmss, + .mtu = nip_mtu, +}; + +static int nip_pkt_discard(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + +static int nip_pkt_discard_out(struct net *net, struct sock *sk, + struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + +struct nip_rt_info *nip_addrconf_dst_alloc(struct ninet_dev *idev, + const struct nip_addr *addr) +{ + u32 tb_id; + struct net *net = dev_net(idev->dev); + struct net_device *dev = idev->dev; + struct nip_rt_info *rt; + + rt = nip_dst_alloc(net, dev, DST_NOCOUNT); + if (!rt) + return ERR_PTR(-ENOMEM); + + nin_dev_hold(idev); + + rt->dst.flags |= DST_HOST; + rt->dst.input = nip_input; + rt->dst.output = nip_output; + rt->rt_idev = idev; + + rt->rt_protocol = RTPROT_KERNEL; + rt->rt_flags = RTF_UP | RTF_NONEXTHOP; + rt->rt_flags |= RTF_LOCAL; + + rt->gateway = *addr; + rt->rt_dst = *addr; + tb_id = NIP_RT_TABLE_LOCAL; + rt->rt_table = nip_fib_get_table(net, tb_id); + + return rt; +} + +struct arg_dev_net { + struct net_device *dev; + struct net *net; +}; + +/* Determine whether an RT should be deleted along with ifDown + * called with nip_tb_lock held for table with rt + */ +static int nip_fib_ifdown(struct nip_rt_info *rt, void *arg) +{ + const struct arg_dev_net *adn = arg; + const struct net_device *dev = adn->dev; + + if ((rt->dst.dev == dev || !dev) && + rt != adn->net->newip.nip_null_entry && + rt != adn->net->newip.nip_broadcast_entry && + ((dev && netdev_unregistering(dev)) || + !rt->rt_idev->cnf.ignore_routes_with_linkdown)) + return -1; + + return 0; +} + +void nip_rt_ifdown(struct net *net, struct net_device *dev) +{ + struct arg_dev_net adn = { + .dev = dev, + .net = net, + }; + + nip_fib_clean_all(net, nip_fib_ifdown, &adn); +} + +static int __net_init nip_route_net_init(struct net *net) +{ + int ret = -ENOMEM; + + memcpy(&net->newip.nip_dst_ops, &nip_dst_ops_template, + sizeof(net->newip.nip_dst_ops)); + + if (dst_entries_init(&net->newip.nip_dst_ops) < 0) + goto out; + + net->newip.nip_null_entry = kmemdup(&nip_null_entry_template, + sizeof(*net->newip.nip_null_entry), + GFP_KERNEL); + if (!net->newip.nip_null_entry) + goto out_nip_dst_entries; + net->newip.nip_null_entry->dst.ops = &net->newip.nip_dst_ops; + dst_init_metrics(&net->newip.nip_null_entry->dst, dst_default_metrics.metrics, true); + + net->newip.nip_broadcast_entry = + kmemdup(&nip_broadcast_entry_template, + sizeof(*net->newip.nip_broadcast_entry), + GFP_KERNEL); + if (!net->newip.nip_broadcast_entry) + goto out_nip_null_entry; + net->newip.nip_broadcast_entry->dst.ops = &net->newip.nip_dst_ops; + dst_init_metrics(&net->newip.nip_broadcast_entry->dst, dst_default_metrics.metrics, true); + ret = 0; +out: + return ret; + +out_nip_null_entry: + kfree(net->newip.nip_null_entry); +out_nip_dst_entries: + dst_entries_destroy(&net->newip.nip_dst_ops); + goto out; +} + +static void __net_exit nip_route_net_exit(struct net *net) +{ + kfree(net->newip.nip_broadcast_entry); + kfree(net->newip.nip_null_entry); + dst_entries_destroy(&net->newip.nip_dst_ops); +} + +static struct pernet_operations nip_route_net_ops = { + .init = nip_route_net_init, + .exit = nip_route_net_exit, +}; + +static int nip_route_dev_notify(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct net *net = dev_net(dev); + + if (!(dev->flags & IFF_LOOPBACK)) + return NOTIFY_OK; + + if (event == NETDEV_REGISTER) { + net->newip.nip_null_entry->dst.dev = dev; + net->newip.nip_null_entry->rt_idev = nin_dev_get(dev); + + net->newip.nip_broadcast_entry->dst.dev = dev; + net->newip.nip_broadcast_entry->rt_idev = nin_dev_get(dev); + } else if (event == NETDEV_UNREGISTER && + dev->reg_state != NETREG_UNREGISTERED) { + nin_dev_put_clear(&net->newip.nip_null_entry->rt_idev); + nin_dev_put_clear(&net->newip.nip_broadcast_entry->rt_idev); + } + + return NOTIFY_OK; +} + +static void seq_printf_nipaddr_to_proc(struct seq_file *seq, + struct nip_addr *addr) +{ + int i = 0; + + for (i = 0; i < addr->bitlen / NIP_ADDR_BIT_LEN_8; i++) + seq_printf(seq, "%02x", addr->nip_addr_field8[i]); + + seq_puts(seq, "\t"); +} + +static void nip_route_show_table(struct seq_file *seq, + struct nip_fib_table *table) +{ + struct nip_fib_node *fn; + int i; + + rcu_read_lock_bh(); + for (i = 0; i < NIN_ROUTE_HSIZE; i++) { + hlist_for_each_entry_rcu(fn, &table->nip_tb_head[i], + fib_hlist) { + struct nip_rt_info *rt = fn->nip_route_info; + + seq_printf_nipaddr_to_proc(seq, &rt->rt_dst); + seq_printf_nipaddr_to_proc(seq, &rt->gateway); + seq_printf(seq, "%4u %4s\n", rt->rt_flags, + rt->dst.dev ? rt->dst.dev->name : ""); + } + } + rcu_read_unlock_bh(); +} + +static int nip_route_proc_show(struct seq_file *seq, void *v) +{ + struct net *net = seq->private; + + nip_route_show_table(seq, net->newip.nip_fib_main_tbl); + nip_route_show_table(seq, net->newip.nip_fib_local_tbl); + + return 0; +} + +static int __net_init nip_route_net_init_late(struct net *net) +{ + proc_create_net_single("nip_route", 0444, net->proc_net, + nip_route_proc_show, NULL); + return 0; +} + +static void __net_exit nip_route_net_exit_late(struct net *net) +{ + remove_proc_entry("nip_route", net->proc_net); +} + +static struct pernet_operations nip_route_net_late_ops = { + .init = nip_route_net_init_late, + .exit = nip_route_net_exit_late, +}; + +static struct notifier_block nip_route_dev_notifier = { + .notifier_call = nip_route_dev_notify, + .priority = ADDRCONF_NOTIFY_PRIORITY - 10, +}; + +int __init nip_route_init(void) +{ + int ret; + + ret = -ENOMEM; + + nip_dst_ops_template.kmem_cachep = + kmem_cache_create("nip_dst_cache", sizeof(struct nip_rt_info), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!nip_dst_ops_template.kmem_cachep) + goto out; + + ret = register_pernet_subsys(&nip_route_net_ops); + if (ret) + goto out_kmem_cache; + + ret = nip_fib_init(); + if (ret) + goto out_register_subsys; + + ret = register_pernet_subsys(&nip_route_net_late_ops); + if (ret) + goto out_nip_fib_init; + + ret = register_netdevice_notifier(&nip_route_dev_notifier); + if (ret) + goto out_register_late_subsys; + +out: + return ret; + +out_register_late_subsys: + unregister_pernet_subsys(&nip_route_net_late_ops); +out_nip_fib_init: + nip_fib_gc_cleanup(); +out_register_subsys: + unregister_pernet_subsys(&nip_route_net_ops); +out_kmem_cache: + kmem_cache_destroy(nip_dst_ops_template.kmem_cachep); + goto out; +} + +void nip_route_cleanup(void) +{ + unregister_pernet_subsys(&nip_route_net_late_ops); + nip_fib_gc_cleanup(); + unregister_pernet_subsys(&nip_route_net_ops); + kmem_cache_destroy(nip_dst_ops_template.kmem_cachep); +} + -- Gitee